volatile的可见性

volaile仅能保证可见性,不能保证原子性。即一个线程对共享变量的修改,其它线程可见。

这是本地测试的,参考了https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247483916&idx=1&sn=89daf388da0d6fe40dc54e9a4018baeb&chksm=eb53873adc240e2cf55400f3261228d08fc943c4f196566e995681549c47630b70ac01b75031&scene=21

package threadTest;

public class volatileTest {
    public static volatile boolean isStop =false;//
    public static void stopIt()
    {
        isStop = true;
    }
    
    public static void main(String[] args) throws InterruptedException
    {
        MyThread mt = new MyThread(5);
        new Thread(mt).start();
        long start = System.currentTimeMillis();
        /*isStop是volatile修饰的,因而当其被其它线程修改时,主线程是可见的,
         * 因而当mt执行后isStop被修改了,while循环结束
         */
        while(!isStop)
        {    
        }
        System.out.println("stop");
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
    
    static class MyThread implements Runnable
    {
        private int times;
        public void run()
        {
            try{
                Thread.sleep(times*1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            stopIt();
        }
        
        public MyThread(int times)
        {
            this.times = times;
        }
        
    }

}

看到主线程在指定的时间后结束了。如果不加volatile修饰,则mt线程对isStop的修改在mt线程结束后同步回主内存,但是主线程的while循环总是从线程空间读取,而自己又没有改变它,因而这里成了一个死循环。

即volatile保证了其修饰的变量的可见性,某个线程对这个变量的修改会立马同步到主内存,而所有线程对这个变量的读取每次都从主内存读取。

读多写少的场景

对于读多写少的场景,可以用volatile保证变量可见性,用synchronized修饰修改的方法,达到线程安全的目的

 

public class volatileTest {
    
    public static volatile long n =0;//volatile
    public static synchronized void add()//
    {
        n++;
    }
    
    public static void main(String[] args) throws InterruptedException
    {
        for(int i=0;i<1000;i++)
        {   
            Thread th = new Thread(new MyThread2());
            th.start();
            //th.join();
            //new Thread(new MyThread2()).start();
        }
        
        while(n<2000000)
        {

            /*这里发现一个有意思的现象,在n不加volatile修饰时,若这里不做任何操作的时候,主线程会一直卡主,但是循环中创建的线程其实是输出了2000000的;而输出n之后所有的线程都会很快执行。说明虽然n最后修改成了正确的值,主线程最后也获得了CPU使用权,但是它的线程空间保存的却不是最终值,因为没有保证变量n的可见性。但是打印n的值为什么又刷新了呢?*/
            //System.out.println("n的值:"+n);
        }
        long end = System.currentTimeMillis();
        System.out.println("执行时间:"+(end-start));
        System.out.println("stop");
    }
    
    static class MyThread2 implements Runnable
    {
        
        public void run()
        {
            try{
                Thread.sleep(1);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            for(long i=0;i<2000;i++)
            {
                add();
            }
            System.out.println(Thread.currentThread().getName()+":" +n);
        }     
    }
}

由volatile保证可见性,由synchronized保证修改操作的原子性。

当然,对于本例中的场景,使用注释中的join()方法也能保证结果的正确性
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值