zoukankan      html  css  js  c++  java
  • volatile关键字

    请你谈谈对volatile关键字的理解

    volatile是Java虚拟机的轻量级的同步机制,具有三个特性:

    1. 保证可见性
    2. 不保证原子性
    3. 禁止指令重排

    1.可见性:当一个线程修改了主线程的值,其他的线程可以立即通知其他线程值被修改了

    2.原子性:一个线程正在做某个操作时,中途不能被加塞/分割,需要整体执行的完整,要么同时成功,要么同时失败

    3.指令重排:处理器在进行重排序之前要考虑最终的执行结果和代码顺序结果的一致性,进行指令重排的操作,必须要

    考虑数据的依赖性.由于在多线程的环境中,数据交互执行,由于编译器指令优化重排序的存在,多个线程中使用的数据

    的一致性是无法确定的,而volatile通过插入内存屏障,禁止内存屏障前后的指令执行进行重排序优化.

    可见性代码:

     1 class MyData{
     2 
     3     int number = 0; //没有加入volatile关键字
     4 
     5     public void change(){
     6         this.number = 60;
     7     }
     8 }
     9 
    10 public static void seeValueByVolatile(){
    11         MyData myData = new MyData();
    12         new Thread(() -> {
    13             System.out.println(Thread.currentThread().getName() + "	"+ myData.number);
    14 
    15             try {
    16                 TimeUnit.SECONDS.sleep(3);
    17             } catch (InterruptedException e) {
    18                 e.printStackTrace();
    19             }
    20             myData.change();
    21             System.out.println(Thread.currentThread().getName() + "	"+ myData.number);
    22         },"可见性测试").start();
    View Code

     两个线程的数据并不同步

    class MyData{
    
        volatile int number = 0; //添加volatile关键字
    
        public void change(){
            this.number = 60;
        }
    }
    
    public static void seeValueByVolatile(){
            MyData myData = new MyData();
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "	"+ myData.number);
    
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                myData.change();
                System.out.println(Thread.currentThread().getName() + "	"+ myData.number);
            },"可见性测试").start();
    
    
    
            while (myData.number == 0){
    
            }
            System.out.println(Thread.currentThread().getName() + "	" + myData.number);
        }
    View Code

     两个线程的数据同步一致

     原子性代码:

     开启20个线程执行number++1000次,最终的结果应该是20000

    class MyData{
    
        volatile int number = 0;
    
        public void change(){
            this.number = 60;
        }
    
        //number++ 被拆分为3个指令,执行getfield获取原始的值,执行iadd进行加1操作,执行putfield写把累加后的值写回到主内存
        public void addPlus(){
            number++;
        }
    
    }
    
     public static void atomicByVolatile(){
            MyData myData = new MyData();
    
            for (int i = 1; i <= 20; i++) {
                new Thread(() -> {
                    for (int j = 1; j <= 1000; j++) {
                        myData.addPlus();//出现了写丢失的情况
                      
                    }
                },String.valueOf(i)).start();
            }
    
            while (Thread.activeCount() > 2){
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName() + "	" + myData.number);
            System.out.println(Thread.currentThread().getName() + "Atomic Number:" + "	" + myData.atomicInteger);
        }
    View Code

     但由于线程争抢,写丢失的情况存在,导致数值的丢失

     解决方法:使用原子引用类

    class MyData{
    
        volatile int number = 0;
    
        public void change(){
            this.number = 60;
        }
    
        //number++ 被拆分为3个指令,执行getfield获取原始的值,执行iadd进行加1操作,执行putfield写把累加后的值写回到主内存
        public void addPlus(){
            number++;
        }
    
        AtomicInteger atomicInteger =  new AtomicInteger();
        //不使用sync的方式来实现原子性,使用JUC下的AtomicInteger
        public void addPlusAtomic(){
            atomicInteger.getAndIncrement();
        }
    }
    
    public static void atomicByVolatile(){
            MyData myData = new MyData();
    
            for (int i = 1; i <= 20; i++) {
                new Thread(() -> {
                    for (int j = 1; j <= 1000; j++) {
                        //myData.addPlus();//出现了写丢失的情况
                        myData.addPlusAtomic();
                    }
                },String.valueOf(i)).start();
            }
    
            while (Thread.activeCount() > 2){
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName() + "	" + myData.number);
            System.out.println(Thread.currentThread().getName() + "Atomic Number:" + "	" + myData.atomicInteger);
        }
    View Code

     结果正确

     案例完整代码:

     1 import java.util.concurrent.TimeUnit;
     2 import java.util.concurrent.atomic.AtomicInteger;
     3 
     4 public class VolatileDemo{
     5     public static void main(String[] args) {
     6 
     7         seeValueByVolatile();
     8         atomicByVolatile();
     9 
    10     }
    11 
    12     public static void atomicByVolatile(){
    13         MyData myData = new MyData();
    14 
    15         for (int i = 1; i <= 20; i++) {
    16             new Thread(() -> {
    17                 for (int j = 1; j <= 1000; j++) {
    18                     myData.addPlus();//出现了写丢失的情况
    19                     myData.addPlusAtomic();
    20                 }
    21             },String.valueOf(i)).start();
    22         }
    23 
    24         while (Thread.activeCount() > 2){
    25             Thread.yield();
    26         }
    27         System.out.println(Thread.currentThread().getName() + "	" + myData.number);
    28         System.out.println(Thread.currentThread().getName() + "Atomic Number:" + "	" + myData.atomicInteger);
    29     }
    30 
    31     public static void seeValueByVolatile(){
    32         MyData myData = new MyData();
    33         new Thread(() -> {
    34             System.out.println(Thread.currentThread().getName() + "	"+ myData.number);
    35 
    36             try {
    37                 TimeUnit.SECONDS.sleep(3);
    38             } catch (InterruptedException e) {
    39                 e.printStackTrace();
    40             }
    41             myData.change();
    42             System.out.println(Thread.currentThread().getName() + "	"+ myData.number);
    43         },"可见性测试").start();
    44 
    45 
    46 
    47         while (myData.number == 0){
    48 
    49         }
    50         System.out.println(Thread.currentThread().getName() + "	" + myData.number);
    51     }
    52 }
    53 
    54 
    55 class MyData{
    56 
    57     volatile int number = 0;
    58 
    59     public void change(){
    60         this.number = 60;
    61     }
    62 
    63     //number++ 被拆分为3个指令,执行getfield获取原始的值,执行iadd进行加1操作,执行putfield写把累加后的值写回到主内存
    64     public void addPlus(){
    65         number++;
    66     }
    67 
    68     AtomicInteger atomicInteger =  new AtomicInteger();
    69     //不使用sync的方式来实现原子性,使用JUC下的AtomicInteger
    70     public void addPlusAtomic(){
    71         atomicInteger.getAndIncrement();
    72     }
    73 }
  • 相关阅读:
    vue.js代码开发最常见的功能集合
    干货|程序员常去的14个顶级开发社区
    17个Web前端开发工程师必看的国外网站
    识别“百度权重”作弊的方法
    问题与对策:CSS的margin塌陷(collapse)
    程序猿,你们这么拼是找不到妹纸的!
    Jquery UI的datepicker插件使用方法
    初识Ajax---简单的Ajax应用实例
    Ajax解决缓存的5种方法
    Jquery+bootstrap实现静态博客主题
  • 原文地址:https://www.cnblogs.com/luhuajun/p/12124640.html
Copyright © 2011-2022 走看看