java多线程补:充原子性和可见性
参考:http://www.cnblogs.com/mengyan/archive/2012/08/22/2651575.html
原子性:所谓原子性就是不可分割的,比如:在我们编程中直接给变量赋值,这就是不可分割的,就具有原子性,相对的,非原子性就是在编程中步骤被分割的,比如编程中的计算,是分步骤进行的,例如:a+=b,其实编程是分为三步,1、先取出a和b的值 2、计算a+b 3、写入内存。这就是非原子性。
可见性:提到可见性,很多同学就会想到一个关键字 volatile ,没错,在多线程中,解决变量的可见性就是利用了volatile这个修饰词。
多线程变量不可见:当一个线程对一变量a修改后,还没有来得及将修改后的a值回写到主存,而被线程调度器中断操作(或收回时间片),然后让另一线程进行对a变量的访问修改,这时候,后来的线程并不知道a值已经修改过,它使用的仍旧是修改之前的a值,这样修改后的a值就被另一线程覆盖掉了。
多线程变量可见:被volatile修饰的成员变量在每次被线程访问时,都强迫从内存中重读该成员变量的值;而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存,这样在任何时刻两个不同线程总是看到某一成员变量的同一个值,这就是保证了可见性。
举个例子:
编写一个线程类:
public class MyThread4 implements Runnable {private boolean isRun = true;
public boolean isRun() {
return isRun;
}
public void setRun(boolean run) {
isRun = run;
}
@Override
public void run() {
System.out.println("4开始运行了");
while (isRun){
}
}
}
main()方法运行
MyThread4 myThread4 = new MyThread4();Thread thread = new Thread(myThread4);
thread.start();
try {
Thread.sleep(100);
myThread4.setRun(false);
System.out.println("停了吗");
} catch (InterruptedException e) {
e.printStackTrace();
}
看运行结果,会发现线程进入了死循环,myThread4.setRun(false);这行代码并没有使线程重新拿到 isRun 的赋值,这说明线程之间对同一个变量的操作是不可见的。
当我们把 isRun 加上volatile关键字时如下:
public class MyThread4 implements Runnable {private volatile boolean isRun = true;
public boolean isRun() {
return isRun;
}
public void setRun(boolean run) {
isRun = run;
}
@Override
public void run() {
System.out.println("4开始运行了");
while (isRun){
}
}
}
再次运行我们会发现,代码不会进入死循环,由此可见,关键字volatile 保障了线程之间变量的可见性。
拓展:当我们在while循环中加入有synchronized关键字修饰的方法时,比如System.out.println();这时代码也不会陷入死循环,因此synchronized除了保障了原子性外,其实也保障了可见性。因为synchronized无论是同步的方法还是同步的代码块,都会先把主内存的数据拷贝到工作内存中,同步代码块结束,会把工作内存中的数据更新到主内存中,这样主内存中的数据一定是最新的。
以上是 java多线程补:充原子性和可见性 的全部内容, 来源链接: utcz.com/z/390435.html