JMM相关

以下内容均由volatile关键字而引出:

JMM,Java memory modelJMM规定所有变量都需要存放在主内存中,同时每个线程又有自己的工作内存。(主要用作高速缓存。CPU有多级缓存,这个是否同一个概念,有待查证,参考简书:什么是Java内存模型


参考简书又有一篇文章提到过,每条线程都有自己的的工作内存(这可以与CPU的高速缓存类比)。

线程的工作内存中会保存从主存中拷贝过来的副本,线程对变量的所有操作都在工作内存中进行,当程序运行结束,数据将被刷新到主存中去。

引入《深入理解Java虚拟机 第3版》中的原话:
对于SunJDK来说, 它的Windows版与Linux版都是使用一对一的线程模型实现的;
一条Java线程就映射到一条轻量级进程之中,因为Windows和Linux系统提供的线程模型就是一对一的。

所谓轻量级进程就是内核(CPU)线程的一种高级接口……线程的工作内存其实是CPU的寄存器和高速缓存的抽象。


内存可见性?一定!

当一个变量被volatile修饰的时候,任何线程对其更新操作,其他线程都可见,或者说是立即被刷新到主存中?并且强制让其他缓存了该变量的线程的工作内存中内容清空,强制从主存中重新获取。

注意不是让线程直接操作主存数据,而是立即更改后立即刷新到主存中,并且其他线程立即可见。

线程安全?不一定!

使用volatile修饰基本数据类型不能保证原子性

public class TestAtomic {
    private volatile static int index = 0;
    // private static AtomicInteger index = new AtomicInteger(0);
    private static final CountDownLatch latch = new CountDownLatch(3);

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                // index.incrementAndGet();
                index++;
            }
            latch.countDown();
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                // index.incrementAndGet();
                index++;
            }
            latch.countDown();
        });
        Thread thread3 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                // index.incrementAndGet();
                index++;
            }
            latch.countDown();
        });
        thread1.start();
        thread2.start();
        thread3.start();
        latch.await();
        // TimeUnit.MILLISECONDS.sleep(300);
        System.out.println("结果,index = " + index);// 结果小于30000,uncommented AtomicInteger 则可以保证原子性达到30000.
    }
}

禁止指令重排(保证有序性)

何为禁止指令重排?

singleton = new Singleton()可以分为三个过程:
1、划分内存
2、填充对象
3、分配指针
且这三个过程顺序往往是不确定的,但是在单线程中没什么问题,考虑多线程的时候:
如果不添加volatile关键字,则有可能由于JVM优化导致指令重排,变为132,并且虽然加了同步锁,但是在3执行完之后就会释放锁,此时其他线程获取同步锁判断对象仍为null,就开是创建对象咯,此时还是单例吗,就不是咯。

经典的单例DCL

public class Singleton {
    // 禁止指令重新排布
    private static volatile Singleton singleton;
    private Singleton(){}
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容