0
点赞
收藏
分享

微信扫一扫

多线程中的不同区域的变量的安全性问题测试

  1. 如果是方法中的变量,不存在线程安全问题。
  • 方法中的变量代码片段:
public class HasSelfPrivateNum {
    public void addI(String userName) {
	// 这里的num变量是存在于addI这个方法里面的
        int num = 0;
        try {
            if (userName.equals("a")) {
                num = 100;
                System.out.println(" a set over !");
                Thread.sleep(2000);
            } else {
                num = 200;
                System.out.println(" b set over !");
            }
            System.out.println(userName + " num = " + num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  • 线程a:
public class ThreadA extends Thread{
    private HasSelfPrivateNum numRef;
    public ThreadA(HasSelfPrivateNum numRef){
        super();
        this.numRef = numRef;
    }
    @Override
    public void run(){
        super.run();
        numRef.addI("a");
    }
}

  • 线程b:
public class ThreadB extends Thread {
    private HasSelfPrivateNum numRef;
    public ThreadB(HasSelfPrivateNum numRef) {
        super();
        this.numRef = numRef;
    }
    @Override
    public void run() {
        super.run();
        numRef.addI("b");
    }
}

  • 测试类:
public class Run {
    public static void main(String[] args) {
        HasSelfPrivateNum numRef = new HasSelfPrivateNum();
        ThreadA threadA = new ThreadA(numRef);
        threadA.start();
        ThreadB threadB = new ThreadB(numRef);
        threadB.start();
    }
}

  • 测试结果: image.png
  1. 再来测试一下,如果变量不是在方法中,而是在class中,结果如何?
  • 对象仅有一个实例变量,可能被覆盖
public class HasSelfPrivateNum {
    private int num = 0;
    public void addI(String userName) {
        try {
            if (userName.equals("a")) {
                num = 100;
                System.out.println(" a set over !");
                Thread.sleep(2000);
            } else {
                num = 200;
                System.out.println(" b set over !");
            }
            System.out.println(userName + " num = " + num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

其余代码不变进行测试一下: image.png 这里可以看到测试的结果已经变了,a num也已经变成了200,解决的方法最直接的一种就是加上锁。通过再次测试加锁结果可以看到,已经能够保证线程安全,不会发生“脏读”读到其他线程修改结果的情况了。 image.png ==结论:两个线程先后访问同一个对象的同步方法是线程安全的!==

  1. 多个锁多个对象的情况 如果有多个对象的情况下,代码如下:
public class Run {
    public static void main(String[] args) {
        HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
        HasSelfPrivateNum numRef2= new HasSelfPrivateNum();
        ThreadA threadA = new ThreadA(numRef1);
        threadA.start();
        ThreadB threadB = new ThreadB(numRef2);
        threadB.start();
    }
}

测试结果如下: image.png ==结论:关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,所以在上面的示例中,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,前提是多个线程访问的是同一个对象。但如果多个线程访问多个对象,则JVM会创建多个锁。上面的示例就是创建了2个HasSelfPrivateNum.java类的对象,所以就会产生出2个锁。==

  1. 继续测试验证
  • image.png
  • 如果是加上了锁,则会产生同步现象image.png ⚠️ 调用用关键字synchronized声明的方法一定是排队运行的。另外需要牢牢记住“共享”这两个字,只有共享资源的读写访问才需要同步化,如果不是共享资源,那么根本就没有同步的必要。
  1. image.png 结论:

1)A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法。2)A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法则需等待,也就是同步。

举报

相关推荐

0 条评论