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);
    }
}

输出结果:

Volatile关键字失效_第1张图片

你可能感兴趣的:(java)