volatile关键字理解
JMM(JAVA内存模型)
![]()
个人理解:
<1> 假设现在有3个线程t1、t2、t3,需要对主内存中的shareVar进行加1操作,JMM规范要求:这3个线程分别从主内存中拷贝一份shareVar到自己的工作空间中(即m1、m2、m3各存在一份),然后三个线程可以进行加1操作,然后每当一个线程完成了加1操作,就立即把其工作内存中的数据刷新到主内存中,并且通知其它线程更新其工作空间中的值;
<2> 特点:
可见性 : 共享数据在多个线程并发操作时,某个线程修改了共享数据,其它线程可以及时获取到更新通知;
原子性 : 共享数据在多个线程并发操作时,能获取到最新的、正确的值;
有序性 : 共享数据在多个线程并发操作时,不会因某些原因(如:指令重排等)导致共享数据结果出现不一致问题(典型例子:++操作)。
<3> 目前实现JMM规范的技术:synchronized、volatile(不满足原子性)
volatile
// 满足JMM的可见性和有序性
import java.util.concurrent.TimeUnit;
/**
* 测试volatile作用
* JMM三大特性: 可见性;原子性;有序性; JMM是一种规范 volatile是一种轻量级的实现;
* volatile满足: 可见性;有序性(禁止指令重排); 不满足原子性!!!
* 本例测试无volatile场景:
*/
public class VolatileDemo {
public int num = 0;
public void add60() {
this.num += 60;
}
public static void main(String[] args) {
VolatileDemo vd = new VolatileDemo();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+":\t come in");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
vd.add60();
System.out.println(Thread.currentThread().getName()+":\t num = " + vd.num);
}).start();
while (vd.num==0){
}
System.out.println(Thread.currentThread().getName()+":\t num="+vd.num);
}
}
VolatileNotSafeDemo.java
import java.util.concurrent.atomic.AtomicInteger;
/**
* volatile 未能保证原子性 demo
* 测试用例: num=0, 20个线程,每个线程对num加1(执行1000次)
*/
class MyData {
volatile int num = 0;
public void addPlusPlus(){
num++;
}
AtomicInteger ai = new AtomicInteger();
public void addMyAtomic(){
ai.getAndIncrement();
}
}
public class VolatileNotSafeDemo {
volatile int num = 0;
public void addPlusPlus(){
num++;
}
public static void main(String[] args) {
MyData vnd = new MyData();
for(int i=0;i<20;i++) {
new Thread(()->{
for(int j=0;j<1000;j++){
vnd.addPlusPlus();
}
},String.valueOf(i)).start();
}
// main线程 && gc线程 : 此时代表所有线程(除前述的两个)执行完毕
while(Thread.activeCount()>2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"\t num="+vnd.num);
}
}
解决volatile不满足原子性的方案
- 使用synchronized关键字
- 使用JUC包下面的Atomic类(如AtomicInteger) ,解决++数据不一致问题
VolatileSafeWithAtomicDemo.java
import java.util.concurrent.atomic.AtomicInteger; /** * volatile 不使用synchronized 保证原子性 demo * 测试用例: num=0, 20个线程,每个线程对num加1(执行1000次) */ class MyData2 { volatile int num = 0; public void addPlusPlus(){ num++; } AtomicInteger ai = new AtomicInteger(); public void addMyAtomic(){ ai.getAndIncrement(); } } public class VolatileSafeWithAtomicDemo { public static void main(String[] args) { MyData2 vnd = new MyData2(); for(int i=0;i<20;i++) { new Thread(()->{ for(int j=0;j<1000;j++){ vnd.addPlusPlus(); // 保证原子性 vnd.addMyAtomic(); } }).start(); } // main线程 && gc线程 : 此时代表所有线程(除前述的两个)执行完毕 while(Thread.activeCount()>2){ Thread.yield(); } System.out.println(Thread.currentThread().getName()+" int type ,finally number value: \t num="+vnd.num);// num=19991 System.out.println(Thread.currentThread().getName()+" AtomicInteger type, finally number value :\t num="+vnd.ai);// num=20000 } }


浙公网安备 33010602011771号