美文网首页
Java多线程之可见性(一)

Java多线程之可见性(一)

作者: NEU_PROYZ | 来源:发表于2018-05-05 22:09 被阅读8次

引言:上一篇文章我们详细地讲了一下什么叫原子性,其中提到了用互斥变量来控制两个线程对缓冲区的访问,即wait()和signal()操作。
我们说在一个线程执行wait()操作进入临界区之后,对于另一个想访问的线程来说,由于mutex=0而进入不了临界区,这其实是不准确的。在其他线程看来,此时mutex值还可能是1。那么问题究竟出在哪呢,其实就是可见性问题。
有一个很重要的例子,摘自《Effective Java》第6条,来和大家一起进入可见性的学习。(怎么贴代码呢=o=用的不是很熟)

public class StopThread {
    private static boolean stopRequested;
    
    public static void main(String[] args) throws InterruptedException {
            
        Thread backgroundThread = new Thread(new Runnable() {

            public void run() {
                // TODO Auto-generated method stub
                int count=0;
                while(!stopRequested) {
                    count++;
                }
            }
        });
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

OK,代码很简单,我们分析一下。程序里面总共两个线程,一个主线程(main),一个子线程(backgroundThread)。StopThread有一个共享的布尔变量stopRequested。子线程通过判断该布尔变量来决定是否执行循环块代码,即count++操作。那么,在我们开始主线程之后,程序大概会经历多久停下来呢?(注意静态变量stopRequested默认是false)。你可能会说,由于主线程停止了1秒后才修改的布尔变量为true,所以,子线程大概会经过1秒执行完整个run()方法,也就是说整个程序大概会运行1秒钟。直接看结果吧:这个循环将一直执行下去!!!

这个问题的根源就在于多线程对共享变量的可见性!!
还是先来书上的定义:如果一个线程对于某个共享变量的进行更新之后,后续访问该变量的线程可以读取到该更改的结果,那么我们就说这个线程对于共享变量的的更新是可见的。
有点基础的朋友可能就恍然大悟,对于初次接触的同学还不好理解。问题就出在java的内存模型上!!!先明白几点:
1.线程都有自己私有的工作区域(通常指寄存器),区别于主存或高速缓存。
2.这种设计的原因是,访问主存的速率是很慢的,线程要用共享变量时是将共享变量拷贝一份到自己的私有内存,之后再更新回去。
3.因此这就涉及到什么时候把值更新回去,以及其他线程看到的是不是更新后的值。
开篇的例子中出的问题在于:子线程并没有到内存里面去读新值,所以一直跳不出循环。这里还涉及jit编译器对循环体热点代码的优化,有兴趣的同学可以自己去查一下。

好了,问题已经给大家说清楚了,那么我们要怎么去解决这个问题呢?
其实很简单,就是让线程在读取共享变量时都到主存去取这个新值,在修改了这共享变量后都及时地写回主存就好了。
这里给大家介绍一个关键字volatile,我以一个看似过来人的语气告诉你,这是面试官钟爱的考点,嘿嘿>o<!
所以我们只需要用volatile修饰stopRequested就可以了。大家可以试一试哦,嗯,关于底层实现下一次再讲,回寝室!

相关文章

  • 深度解析volatile—底层实现

    我们都知道,Java关键字volatile的作用 1、内存可见性2、禁止指令重排序 可见性是指,在多线程环境,共享...

  • Java并发实践

    Java Concurrency 在多线程环境下,为了保证共享数据的原子和内存可见性,需要进行锁操作。在JAVA中...

  • Java多线程系列之可见性

    何为可见性? 线程A修改了共享变量Var1,线程B能看到这个修改吗?这就是所谓的可见性。在多线程的世界里,每个线程...

  • java并发中volatile的使用

    java中volatile声明变量,有两个作用 保证变量对所有线程的可见性 禁止指令重排 保证可见性 多线程访问共...

  • Java 锁机制详解(二)volatile

    上接 Java 锁机制详解(一)synchronized 一、 多线程隐患 1. 内存可见性 在赋值变量时,会经历...

  • volatile的原理和使用

    1.对线程的可见性 Java的volatile关键字声明使变量对不同线程具有可见性。程序在多线程操作non-vol...

  • java内存结构和java内存模型

    java内存模型:与多线程JMM,就是线程可见性有关java内存结构:JVM虚拟机存储空间 class文件被类加载...

  • Java多线程可见性

    一:内存可见性 线程对共享变量的修改,可以及时的被其他线程看到。那何为共享变量呢?就是在多个线程的工作内存中存在如...

  • Java 多线程可见性

    在现代操作系统上编写并发程序时,除了要注意线程安全性(多个线程互斥访问临界资源)以外,还要注意多线程对共享变量的可...

  • Java 内存模型 JMM 浅析

    Java Memory Model简称JMM, 是一系列的Java虚拟机平台对开发者提供的多线程环境下的内存可见性...

网友评论

      本文标题:Java多线程之可见性(一)

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