zoukankan      html  css  js  c++  java
  • volatile关键字的特性及证明

    volatile是java虚拟机提供的轻量级的同步机制

    JMM(Java内存模型)是围绕着并发编程中原子性、可见性、有序性这三个特征来建立的

    原子性:一个操作或多个操作要么全部执行完成且执行过程不被中断,要么就不执行。

    可见性:当多个线程同时访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

    有序性:程序执行的顺序按照代码的先后顺序执行。

    volatile保证了可见性,有序性,不保证原子性

    证明可见性的代码:

     1 package concurrent;
     2 
     3 import java.util.concurrent.TimeUnit;
     4 
     5 /*
     6  * @description: volatile特性
     7  * @date 2019.04.22 20:48
     8  */
     9 //数据类
    10 class Mydata{
    11 
    12     volatile int num = 0;
    13 
    14     public void changeNum(){
    15         this.num = 100;
    16     }
    17 }
    18 
    19 public class VolatileDemo {
    20 
    21     public static void main(String[] args)  throws InterruptedException{
    22         Mydata mydata = new Mydata();
    23         new Thread(() -> {
    24             System.out.println("===="+Thread.currentThread().getName() +"线程启动===");
    25             //暂停3秒
    26             try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {}
    27             //3秒后t1线程改变num的值
    28             mydata.changeNum();
    29             System.out.println(Thread.currentThread().getName()+"线程将num的值改为"+mydata.num);
    30         },"t1").start();
    31 
    32         //num的值不变就一直循环
    33         long begin = System.currentTimeMillis();
    34         while (mydata.num == 0){
    35             //num如果不被volatile修饰会一直循环
    36         }
    37         long cost = System.currentTimeMillis() - begin;
    38         System.out.printf(Thread.currentThread().getName()+"线程检测到num的值已经改变,cost{%d},证明了volatile的可见性",cost);
    39     }
    40 }

    运行结果为:

    ====t1线程启动===
    t1线程将num的值改为100
    main线程检测到num的值已经改变,cost{3001},证明了volatile的可见性
    

      

    证明不保证原子性的代码:

    class Mydata{
    
        volatile int num = 0;
    
        public void changeNum(){
            this.num = 100;
        }
    
        public void numIncreOne(){
            this.num++;
        }
    }
    
    public class VolatileDemo {
        
        public static void main(String[] args)  throws InterruptedException{
    
            Mydata mydata = new Mydata();
            //开启10个线程每个线程调用1000次num++
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    for (int j = 0; j < 1000; j++) {
                        mydata.numIncreOne();
                    }
                },String.valueOf(i)).start();
            }
    
            //输出num的值,如果volatile能保证原子性num将等于10000
            System.out.println(mydata.num);
            System.out.println(mydata.num ==10000?"volatile可以保证原子性":"volatile无法保证原子性");
        }
    }

    输出结果:

    5856
    volatile无法保证原子性

    多线程环境中,线程交替执行,编译器会通过对指定进行重排序来进行优化。被volatile修饰的变量不会参与重排序,保证有序性。

    证明有序性的代码:

     1     int num = 0;
     2 
     3     private boolean flag = false;
     4     
     5     private void reSort1(){
     6         num = 1;    //语句1
     7         flag = true; //语句2
     8     }
     9 
    10     private void reSort2(){
    11         if(flag){
    12             num++;
    13             System.out.println("num的值为"+num);
    14         }
    15     }
    多线程情况下有可能先执行语句2,再执行语句1,从而导致num只自增1次,输出为1。
  • 相关阅读:
    SQL第一讲
    CSS3补充内容
    EXCEL数据导入SQL表的方法
    jq第四讲+实例
    jq第三讲
    jq第二讲
    安卓、苹果日历同步
    安卓、苹果手机备忘录同步
    服务器、客户端双认证
    今天我的博客正式开张了!
  • 原文地址:https://www.cnblogs.com/dream2true/p/10753625.html
Copyright © 2011-2022 走看看