volatile 关键字(volatile:易变的,反复无常的)
声明此变量值是不稳定的,每次使用它都到主存中进行读取,而且当成员变量发生变化时,强迫线程将变化值回写到共享内存中。且不会将该变量上的操作与其他内存操作一起重排序。
volatile 是一种 synchronized 的简化,他并不会执行加锁操作,所以不会阻塞执行线程。
volatile 只确保每线程执行时从主内存拿数据,而不能使用自己的缓存。但由于没有使用锁机制,因此不能保证更新主内存中的值的时候是线程安全的。如 volatile a=5,两个线程同时执行 a++操作,当他们从主内存拿数据时,都是拿出来的5,线程1执行完+1后,将6覆盖主内存中的a,此时线程2也同时加1后用6覆盖主内存中的1,所以当两个线程都执行完毕后,主内存中的 a=6,而非我们希望看到的 a=7。
因此,需要线程绝对安全时,只使用 volatile 是绝对不行的,还是要用 synchronized 同步。但 volatile 由于没有使用锁,因此执行效率要比 synchronized 高很多。
执行 VolatileAndSyncTest.inc(); 方法时,结果总是随机的,基本得不到期望的1000,总是993,995之类的随机结果
执行 VolatileAndSyncTest.incBySync(); 方法时,由于使用了同步机制,因此可以保证结果是我们想要的1000,但由于各个线程排队执行,也就基本上失去了多线程并发执行的优势,执行效率很低。
声明此变量值是不稳定的,每次使用它都到主存中进行读取,而且当成员变量发生变化时,强迫线程将变化值回写到共享内存中。且不会将该变量上的操作与其他内存操作一起重排序。
volatile 是一种 synchronized 的简化,他并不会执行加锁操作,所以不会阻塞执行线程。
volatile 只确保每线程执行时从主内存拿数据,而不能使用自己的缓存。但由于没有使用锁机制,因此不能保证更新主内存中的值的时候是线程安全的。如 volatile a=5,两个线程同时执行 a++操作,当他们从主内存拿数据时,都是拿出来的5,线程1执行完+1后,将6覆盖主内存中的a,此时线程2也同时加1后用6覆盖主内存中的1,所以当两个线程都执行完毕后,主内存中的 a=6,而非我们希望看到的 a=7。
因此,需要线程绝对安全时,只使用 volatile 是绝对不行的,还是要用 synchronized 同步。但 volatile 由于没有使用锁,因此执行效率要比 synchronized 高很多。
write by 开发老张
例:
package com.zsoft.test;
/**
* 测试 Volatile 和 synchronized 的线程安全差别
* @author zsoft
*
*/
public class VolatileAndSyncTest {
public volatile static int count=0;
public static void inc(){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
public synchronized static void incBySync(){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
public static void main(String[] args) {
for(int i=0;i<1000;i++){
new Thread(new Runnable() {
@Override
public void run() {
//VolatileAndSyncTest.inc(); //非同步方法
VolatileAndSyncTest.incBySync(); //同步方法
}
}).start();
}
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("运行结果:VolatileAndSyncTest.count="+VolatileAndSyncTest.count);
}
}
执行 VolatileAndSyncTest.inc(); 方法时,结果总是随机的,基本得不到期望的1000,总是993,995之类的随机结果
执行 VolatileAndSyncTest.incBySync(); 方法时,由于使用了同步机制,因此可以保证结果是我们想要的1000,但由于各个线程排队执行,也就基本上失去了多线程并发执行的优势,执行效率很低。