JUC系列之(二)volatile关键字

volatile关键字-内存可见性

引出内存可见性问题的示例:

package com.atguigu.juc;

public class TestVolatile {
    public static void main(String[] args) {
        // 线程threadDemo修改共享变量的值
        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo).start();

        // main线程读取共享变量的值
        while (true){
            if (threadDemo.isFlag()){
                System.out.println("------------------");
                break;
            }
        }
    }
}

class ThreadDemo implements Runnable {
    private boolean flag = false;

    public boolean isFlag() {
        return flag;
    }

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

    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {

        }
        flag = true;

        System.out.println("flag=" + isFlag());
    }
}

一直没有执行结束,像是main线程读取的共享变量的值一直都是false,导致main线程一直没有结束

内存可见性问题:

多个线程由于存在独立的缓存,因此在操作共享数据时彼此是不可见的(一个线程操作了共享变量之后,另一个线程看到的共享变量的状态还是改变之前的)

解决内存可见性问题:

通过同步锁可以解决内存可见性问题

package com.atguigu.juc;

public class TestVolatile {
    public static void main(String[] args) {
        // 线程threadDemo修改共享变量的值
        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo).start();

        // main线程读取共享变量的值
        while (true){
            // 同步锁能够保证main线程每次都能刷新缓存,去主存中读数据,保证每次读到的共享数据都是最新的
            synchronized (threadDemo) {
                if (threadDemo.isFlag()){
                    System.out.println("------------------");
                    break;
                }
            }
        }
    }
}

class ThreadDemo implements Runnable {
    private boolean flag = false;

    public boolean isFlag() {
        return flag;
    }

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

    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {

        }
        flag = true;

        System.out.println("flag=" + isFlag());
    }
}

volatile关键字:既想解决内存可见性问题,又不想通过加同步锁的方式解决(加锁后效率极低),因此出现了该关键字

当多个线程进行操作共享数据时,可以保证内存中的数据可见。(一个线程操作了共享变量之后,另一个线程能够马上看到共享变量状态的变化)

使用了volatile关键字,就相当于线程1是直接改的主存中的共享变量,main线程是实时从主存中读取的共享变量的值。

volatile关键字原理:内存栅栏

volatile关键字造成性能下降的原因:被volatile关键字修饰后,不能再进行重排序了

package com.atguigu.juc;

public class TestVolatile {
    public static void main(String[] args) {
        // 线程threadDemo修改共享变量的值
        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo).start();

        // main线程读取共享变量的值
        while (true){
            if (threadDemo.isFlag()){
                System.out.println("------------------");
                break;
            }
        }
    }
}

class ThreadDemo implements Runnable {
    // 使用volatile关键字修饰共享变量
    private volatile boolean flag = false;

    public boolean isFlag() {
        return flag;
    }

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

    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {

        }
        flag = true;

        System.out.println("flag=" + isFlag());
    }
}

解决了内存可见性问题就相当于各个线程在直接操作主存中的数据

volatile和synchronized的比较:

volatile仅仅是更轻量级的一种同步策略

volatile不具备“互斥性”
volatile不能保证变量的“原子性”

posted @   刘二水  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示