美文网首页
volatile关键字与内存可见性

volatile关键字与内存可见性

作者: 不知名的蛋挞 | 来源:发表于2018-10-22 09:37 被阅读23次

    转载文章:https://www.cnblogs.com/ccfdod/p/6392343.html

    举例说明

    首先,我们先看一段小程序。

    package com.ccfdod.juc;
    
    public class TestVolatile {
        public static void main(String[] args) {
            ThreadDemo td = new ThreadDemo();
            new Thread(td).start();
            
            while(true) {
                if (td.isFlag()) {
                    System.out.println("--------------");
                    break;
                }
            }
        }
    }
    
    class ThreadDemo implements Runnable {
        private boolean flag = false;
    
        @Override
        public void run() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true;
            System.out.println("flag = " + isFlag());
        }
    
        public boolean isFlag() {
            return flag;
        }
    
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    }
    

    程序运行结果:

    flag = true
    

    并且程序不会停止。

    按理来说,应该会在td线程修改flag值后,主线程会打印出“--------------”,但是为什么没有出现预期效果呢?下面来分析这段程序,涉及到内存可见性问题。

    内存可见性问题

    当程序运行时,JVM会为每一个执行任务的线程分配一个独立的缓存空间,用于提高效率。

    不难理解,程序开始执行时,由于线程td修改flag操作之前,sleep了200ms,td线程和main线程获取到的flag都为false,但为什么td线程将flag改为true后,main线程没有打印出“--------------”呢?原因在于:while(true)是执行效率很高,使得main线程没有时间再次从主存中获取flag的值,因此程序在td线程将flag修改为true后,没有停止运行的原因。其实在while(true)后面稍微延迟一点(比如说,打印一句话),都会使main线程将主存中的flag=true读取。

    产生这种情况的原因就在于,两个线程在操作共享数据时,对共享数据的操作是彼此不可见的。

    那么为了不让这种问题出现,怎么解决呢?

    (1)使用synchronized同步锁

    while(true) {
        synchronized (td) {
            if (td.isFlag()) {
                System.out.println("--------------");
                break;        
            }
        }
    }
    

    使用synchronized同步锁能保证数据的及时更新。但是效率太低。

    (2)使用volatile关键字

    当多个线程进行操作共享数据时,可以保证内存中的数据可见。底层原理:内存栅栏。使用volatile关键字修饰时,可理解为对数据的操作都在主存中进行。

    private volatile boolean flag = false;
    

    相较于synchronized是一种较为轻量级的同步策略。

    相关文章

      网友评论

          本文标题:volatile关键字与内存可见性

          本文链接:https://www.haomeiwen.com/subject/vdywzftx.html