一。volatile是java虚拟机提供的轻量级的同步机制
1.保证可见性
1.1 假如 int number = 0;number变量之前没有添加volatile,没有可见性,不会走到第三步
1.2 number变量之前添加volatile,具有可见性,3秒之后会走到第三步
1 class MyData { 2 volatile int number = 0; 3 4 public void addTo60() { 5 this.number = 60; 6 } 7 } 8 9 public class VolatileDemo { 10 public static void main(String[] args){ 11 seeOkByVolatile(); 12 } 13 public static void seeOkByVolatile() { 14 MyData myData = new MyData(); 15 new Thread(() -> { 16 System.out.println(Thread.currentThread().getName()+" start");// 第一步 17 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } 18 myData.addTo60(); 19 System.out.println(Thread.currentThread().getName()+" update end value: "+myData.number);// 第二步 20 }, "AAA").start(); 21 22 while (myData.number == 0) { 23 24 } 25 System.out.println(Thread.currentThread().getName()+" value:"+myData.number);// 第三步 26 } 27 28 29 }
2.不保证原子性
结果:输出小于20000
原因:number++这个操作实际上可以分为3个步骤
1.从主内存中读取number=0的值,复制到工作内存中
2.在工作内存中进行加1操作
3.将加1后的值赋给主内存
分析:有两个线程T1,T2同时进行number++操作时,当T1进行完1,2,3步骤后 number=1,T2刚执行完1,2还没有执行完3(number = 0 + 1)number=1
有重新赋值给主内存,导致两个线程都对number加1,最终只增加了1次。
方案:怎么保证原子性
1.使用 synchronized
1 class MyData { 2 volatile int number = 0; 3 public void addPluxPlux() { 4 number++; 5 } 6 } 7 public class VolatileDemo { 8 public static void main(String[] args){ 9 MyData myData = new MyData(); 10 for (int i = 0; i < 20; i++) { 11 new Thread(() -> { 12 for (int j = 0; j < 1000; j++) { 13 myData.addPluxPlux(); 14 } 15 },String.valueOf(i)).start(); 16 } 17 while(Thread.activeCount() > 2){ 18 Thread.yield(); 19 } 20 System.out.println("number: "+myData.number); 21 } 22 }
2.使用原子类AtomicInteger
输出结果:number<20000,atomic=20000
1 class MyData { 2 volatile int number = 0; 3 public void addTo60() { 4 this.number = 60; 5 } 6 public void addPluxPlux() { 7 number++; 8 } 9 10 AtomicInteger atomic = new AtomicInteger(); 11 public void atomicAddPlux(){ 12 atomic.incrementAndGet(); 13 } 14 } 15 16 public class VolatileDemo { 17 public static void main(String[] args){ 18 MyData myData = new MyData(); 19 for (int i = 0; i < 20; i++) { 20 new Thread(() -> { 21 for (int j = 0; j < 1000; j++) { 22 myData.addPluxPlux(); 23 myData.atomicAddPlux(); 24 } 25 },String.valueOf(i)).start(); 26 } 27 28 while(Thread.activeCount() > 2){ 29 Thread.yield(); 30 } 31 System.out.println("number: "+myData.number); 32 System.out.println("atomic: "+myData.atomic); 33 34 } 35 }
3.禁止指令重排
指令重排必须要考虑指令之间的数据依赖性