volatile的理解

一。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.禁止指令重排

  指令重排必须要考虑指令之间的数据依赖性

 

 

posted @ 2021-01-27 17:43  郑某人1  阅读(72)  评论(0编辑  收藏  举报