并发变量下变量不可见性问题&&Volatile关键字

5.9 Volatile关键字
5.9.1 并发变量下变量不可见性问题

引入:在多个线程访问共享变量过程中, 一个线程修改变量的值后,其他线程看不到变量最新值的情况。

1、VolatileDemo01线程在run方法中修改flag变量的值为true

@Override
    public void run() {
        flag = true;
        System.out.println(Thread.currentThread().getName()+":"+"flag = " + flag);
    }

2、在Test类中启动VolatileDemo01线程并且在Test主线程中监视flag变量

while (true){
    if(t.isFlag()){
        System.out.println("主线程进入执行");
    }
}

3、运行结果:VolatileDemo01线程将flag修改之后,Test主线程并没有监控到flag有变化,这就是并发变量下变量不可见性问题


5.9.2 变量不可见性的内存语义

在介绍多线程并发修改变量不可见现象的问题原因之前,我们需要了解一下Java内存模型(java并发编程有关的模型):JMM

JMM(Java Memory Model);Java内存模型,是Java虚拟机规范中所定义的一种内存,Java内存模型是标准化的,屏蔽掉了底层不同计算机的区别。

Java内存模型描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节

JMM有一下规定:

  • 所有的共享变量都存储于主内存,这里所说 的变量指的是实例变量和类变量,不包括局部变量,因为局部变量是线程私有的,不存在竞争问题。
  • 每一个线程还存在自己的工作内存,线程的工作内存保留了被线程使用的变量的工作副本
  • 线程对变量的读写操作都是在工作内存中完成,而不是直接读写与主内存中的变量。
  • 不同线程之间不能直接访问对方工作内存中的变量,线程之间的变量传递需要通过主内存中转来完成。

在这里插入图片描述


5.9.3 解决方案(并发变量下变量不可见性问题)

synchronized加锁实现重新将主内存的共享变量拷贝至子线程的工作内存。

while (true){
    synchronized (VolatileDemo01.class){
            if(t.isFlag()){
                System.out.println("主线程进入执行");
            }
        }
}

② 给共享变量加上volatile关键字

private volatile boolean flag;

5.9.4 volatilesynchronized
  • volatile只能修饰实例变量和类变量,而synchronized可以修饰方法以及代码块
  • volatile保证数据的可见性问题,但是不保证原子性(多线程进行缬草组,不保证线程安全)而synchronized是一种排他(互斥)的机制。即volatile不保证线程安全,而synchronized是线程安全的

5.9.5 volitile 关键字

使用volatile修饰的变量的值在被一个线程修后,其他线程可以获取到这个共享变量的最新值

使用volatile修饰共享变量,就可以解决并发变量下变量不可见性问题


完整代码如下:

public class VolatileDemo01 extends Thread{
    // private volatile boolean flag;
    private boolean flag;

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.println(Thread.currentThread().getName()+":"+"flag = " + flag);
    }

    public VolatileDemo01(boolean flag, String name) {
        super(name);
        this.flag = flag;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

class Test {
    public static void main(String[] args) {
//        启动子线程
        VolatileDemo01 t = new VolatileDemo01(false, "子线程");
        t.start();

//        主线程
        while (true){
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+"flag = "+t.isFlag());
//            这里需要使用到VolatileDemo01中的变量
            synchronized (VolatileDemo01.class){
                if(t.isFlag()){
                    System.out.println("-------------------------");
                    System.out.println("主线程进入执行");
                    System.out.println(Thread.currentThread().getName()+":"+"flag = "+t.isFlag());
                    System.out.println("-------------------------");
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值