- 参考Java多线程之volatile 与 synchronized 的比较,感谢博主。理解该篇知识点需要Java内存模型基础。
- 为什么
volatile
是轻量级锁,不能用来保持同步。因为volatile
通过让线程对标记变量进行连续、有序的read、load、use等操作,使得线程对于变量的改变使得其他线程可见(详见《深入理解Jvm》书P372)。它不是通过阻塞线程来实现线程安全的,所以不能用来进行同步。而synchronized通过对变量或者方法进行加锁,一次只有一个线程能获得对应资源,其余线程会进行等待,达到了阻塞的目的,可以用来进行同步。
3.volatile
的非原子性。对于i++操作来说,该操作分为三步,首先从主内存中读取i变量值到工作内存(read,load),然后进行i增加1操作(use,assign),然后将i运算的结果值同步回主内存中(store,wirte),由于volatile不会阻塞线程,有多个线程可以获得该变量值,可能当线程A执行i++操作的第一、二步时,线程B从主内存中获取了i的值,而这时A才将i放回主内存。那么B获得的就是旧的i的值,在《Effective JAVA》中称之为“安全性失败”。因此,仅靠olatile
不能保证线程的安全性(原子性)。可参考如下代码:
public class MyThread extends Thread {
public volatile static int count;
private static void addCount() {
for (int i = 0; i < 100; i++) {
count++;
}
System.out.println("count=" + count);
}
@Override
public void run() {
addCount();
}
}
public class Run {
public static void main(String[] args) {
MyThread[] mythreadArray = new MyThread[100];
for (int i = 0; i < 100; i++) {
mythreadArray[i] = new MyThread();
}
for (int i = 0; i < 100; i++) {
mythreadArray[i].start();
}
}
}
如果是线程安全的,或者使用了synchronized
,那么每个线程最后打印的都会是100,单纯的使用volatile
,发现没有效果,就在于volatile
不能保证原子性。
Java初学,不当之处还请指教