广州飞狐科技有限公司官网
技术文章
2020-12-27 17:35:22

JAVA:Volatile关键字失效

分享到:

volatile关键字用于修饰简单类型变量,如int、float、boolean等数据类型,保证同一时刻只能有一个线程修改变量。

volatile修饰变量的操作就会变成原子级别的,但这有一定的情况会失效:


public class VolatileTEST {
 
    volatile static int val = 0;
 
    public static void  main(String[] args) throws InterruptedException{
        Thread t1 = new Thread(() -> {
            for(int i=0; i<300000; i++){
                val += 1;
            }
        });
        Thread t2 = new Thread(() -> {
            for(int i = 0; i<300000; i++){
                val += 1;
            }
        });
        long startTime =  System.currentTimeMillis();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("时间:" + (System.currentTimeMillis() - startTime) + "毫秒");
        System.out.println(val);
    }
}这个实例期望的是得到600000,但是实际运行结果:

原因是:val +=1 并不是原子操作。 当volatile修饰简单变量,当前值是根据以前的值得到时,例如:val+=1,val=val+1 , val++等,volatile关键字将失效。只有当变量的值和以前的值无关时,对该变量的操作才是原子级别,如val = n + 1。

      这时候需要使用synchronized把操作(例如val+=1)抽取成一个方法:

public class VolatileTest2 {
    static int val = 0;
 
    public static synchronized void inc(){
        val += 1;
    }
 
    public static void  main(String[] args) throws InterruptedException{
        Thread t1 = new Thread(() -> {
            for(int i=0; i<300000; i++){
                inc();
            }
        });
        Thread t2 = new Thread(() -> {
            for(int i = 0; i<300000; i++){
                inc();
            }
        });
        long startTime =  System.currentTimeMillis();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("时间:" + (System.currentTimeMillis() - startTime) + "毫秒");
        System.out.println(val);
    }
}

输出结果:

————————————————
版权声明:本文为CSDN博主「Crzis」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ling_du/article/details/98510821

上一篇:你所不知道的事情: 异步提交的几种方式
下一篇:MYSQL数据库类型与JAVA类型对应表