目 录CONTENT

文章目录

01_JUC_volatile关键字与内存可见性

ByteNews
2019-08-26 / 0 评论 / 0 点赞 / 37,219 阅读 / 1,625 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-01-16,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

01_JUC_volatile关键字与内存可见性

Java JUC简介

在Java5.0提供了java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似线程的自定义子系统,包括线程池、异步IO和轻量级任务框架。提供可调的、灵活的线程池。还提供了设计用于多线程上下文的Collection实现等。

内存可见性

内存可见性问题就是当多个线程操作共享数据的时候,彼此不可见,因此产生此问题。

对于上述问题可以用synchronized来锁,但是效率低,多线程的情况下会造成阻塞。

测试

public class TestVolatile {

    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        new Thread(td).start();
        while (true){
            // 锁确实可以保证数据的即时更新,但是效率非常低,在多线程的时候没获得锁会造成阻塞
            synchronized (td){
                // 这里如果不进行同步synchronized,会发现并不会打印,这里的flag是false的
                if(td.isFlag()){
                    System.out.println("--------------");
                    break;
                }
            }
        }
    }

}

class ThreadDemo implements Runnable{

    public boolean isFlag() {
        return flag;
    }

    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.println("flag = " + flag);
    }

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

    private boolean flag = false;
}

这时候就需要volatile关键字,当多个线程进行操作共享数据时,可以保证内存中的数据是可见的。底层是用计算机底层的代码内存栅栏,实际上是时时刻刻把缓存中的数据刷新到主存。相当于线程每次进行操作共享数据的时候,就像在主存中操作一样。

虽然使用volatile关键字效率也会降低(数据实时更新到主存,且JVM底层有个优化叫重排序,volatile修饰了以后,就不能重排序了),但是相比锁而言,volatile效率会高一些。

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 volatile boolean flag = false;

    public boolean isFlag() {
        return flag;
    }

    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.println("flag = " + flag);
    }

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

相较于synchronized是一种较为轻量级的同步策略,但是使用volatile的时候还是要注意:

  1. volatile不具备”互斥性“;
  2. volatile不能保证变量的“原子性”;
0

评论区