精华内容
参与话题
问答
  • java的内存可见性分析

    2018-09-07 22:09:04
    java多线程之内存可见性 共享变量在线程间的可见性 Synchronized实现可见性 volatile实现可见性  指令重排序  as if -serial语意  volatile使用注意事项 Synchronized和volatile的比较 1.可见性介绍  可见性:...

    java多线程之内存可见性
    共享变量在线程间的可见性
    Synchronized实现可见性
    volatile实现可见性
         指令重排序
         as if -serial语意
         volatile使用注意事项
    Synchronized和volatile的比较

    1.可见性介绍
        可见性:一个线程对共享变量的修改,能够及时的被其他线程看到
        共享变量:如果一个变量在多个线程中存有副本,那么这个变量就是这几个线程的共享变量
        java内存模型(JMM)
        java内存模型(java memory model)描述了java程序中各种变量(线程共享变量)的访问规则,以及在jvm中将变量储存到内存
        和从内存中读取出变量的底层细节。

    2.通过Synchronized和volatile都可以实现可见性
      线程对共享变量的所有操作都必须在自己的工作内存中进行
      所有的变量都储存在主内存中

    3.要实现共享变量的可见性,必须保证二点
      线程修改后的共享变量值能够及时保证从工作内存中刷新到主内存中。
      其他线程能够及时把共享变量的最新值从主内存中刷新到自己的工作内存中去。

    4.可见性的实现方式
    java语言支持的可见性实现方式
    synchronized和volatile
    1.)Synchronized能够实现
    原子性,同步


    JMM关于Synchronized的二条规定:
    1.1 线程解锁前,必须把共享变量的最新值刷新到主内存中去
    1.2 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存重新读取最新的值
    (注意:加锁和解锁需要同一把锁)
    线程解锁前对共享变量的修改在下次加锁时对其他线程可见
    线程执行互斥锁代码的过程
    1,获得互斥锁
    2,清空工作内存
    3,从主内存中拷贝最新副本的变量到工作内存中
    4,执行代码
    5,将更改后共享变量的值刷新到主内存中
    6,释放互斥锁

    重排序:
    代码书写的顺序与实际执行的顺序不同,指令重排序是编译器或处理器为了
    提高程序性能做的优化
    1.编译器优化的重排序(编译器优化)
    2.指令级并行重排序(处理器优化)
    3.内存系统的重排序(处理器优化)

    as-if-serial
    as-if-serial:无论如何重排序,程序执行的效果应该与代码的顺序执行的结果一致
    (java编辑器,运行时和处理器都会保证java在单线程下遵守as-if-serial语句)

    导致共享变量在线程间不可见的原因
    1. 线程的交叉执行                                                                                       原子性
    2. 重排序结合线程交叉执行                                                                         原子性
    3. 共享变量更新后的值没有在工作内存与主内存之间及时更新                    可见性

    展开全文
  • 今天看一下实现内存可见性的方式

    今天看一下实现内存可见性的方式
    首先看一下一些概念:
    可见性:一个线程对共享变量值的修改,能够及时的被其他线程看到。
    共享变量:如果一个变量在每个线程的工作内存中都有副本,那么这个变量就是这些线程的共享变量。

    下面讲一下关于Java内存的一些东西

    • 所有的变量都存储在主内存
    • 每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一个拷贝)

    Synchronized可以实现

    • 原子性
    • 可见性

    Java内存模型的两条规定

    • 线程对共享变量的所有操作必须在自己的工作内存中进行,不能直接从住内存中读写
    • 不同线程直接不能直接访问其他线程工作内存中的变量,线程间变量的传递需要通过主内存。

    指令重排序
    代码的书写顺序和执行顺序不一致,重排序是编译器或者处理器为了提高程序性能所做的优化。

    as-if-serial语义
    无论如何重排序,程序执行的结果应该与代码顺序执行的结果一致。重排序不会给单线程造成内存可见性问题

    if(ready){
    result = number*3;
    }

    上面的代码也可能重排序,只有数据依赖关系才会禁止重排序,上面的代码等同于

    int mid = 3;
    if(ready){
    result = mid;
    }

    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述

    展开全文
  • 多线程-内存可见性

    2019-04-01 16:33:48
    2.内存可见性 在介绍volatile关键字之前,先来看看什么是内存可见性。 那什么是内存可见性呢? 通过一个神奇的程序来引出内存可见性。 例子很简单,一个线程根据循环条件一直循环,另一个线程一段时间后更改其...

    2.内存可见性

    在介绍volatile关键字之前,先来看看什么是内存可见性

    那什么是内存可见性呢?

    通过一个神奇的程序来引出内存可见性

    例子很简单,一个线程根据循环条件一直循环,另一个线程一段时间后更改其循环条件使其变为false,然后观察程序运行情况。

    首先创建一个线程并重写run()方法:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    然后,在run()方法里面根据条件循环,这里我们采用while循环:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    接着,循环条件是判断变量isStop的值(当前循环是否停止),所以我们需要定义一个boolean变量来记录循环是否需要停止:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    run()方法书写完毕。

    然后,启动线程:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    接着,将isStop变量设置为true,即希望线程里面的while循环读到isStop变量为true时停止循环:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    当然了,isStop不是在thread线程启动后立即设置,而是在thread线程启动后1秒去设置:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    例子书写完毕。

    在这里,大家可以猜一下运行结果是什么,肯定出乎你的意料。

    这里就不卖关子了。

    运行程序,执行结果:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    从运行结果来看,跟我们想的不太一样,程序看似停着不动了。

    请问这符合预期吗?

    这是符合预期的,程序看似停着不动,实际上是while循环在不停地运行着没有结束。

    明明isStop变量在经过1秒钟之后被主线程设置为true了,怎么while循环还没有结束呢?

    这里我们还是把isStop变量在启动thread线程前后值的变化输出给大家看一下比较有说服力。

    改写例子,在启动thread线程前输出isStop值:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    在设置完isStop值后输出isStop值:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    例子改写完毕。

    运行程序,执行结果:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    从运行结果来看,符合预期。

    那么就有一个问题:明明isStop的值被改为true,thread线程里面的while循环为什么没有停下来?

    这里就涉及到一个内存可见性问题。

    主线程和thread线程读取isStop过程

    首先说说主线程和thread线程读取isStop过程:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    简单小结一下就是:

    主线程先去缓存中取isStop,发现缓存中没有isStop,于是就去主内存中取isStop。

    同理,thread线程也是先去缓存中取isStop,发现缓存中也没有isStop,于是就去主内存中取isStop。

    现在主线程和thread线程都取得isStop=false。

    thread线程执行while循环,主线程设置isStop=true过程

    再来说说thread线程执行while循环,主线程设置isStop=true过程:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    简单小结一下就是:

    thread线程执行while循环,while循环条件中需要用到isStop,于是thread线程就去取isStop,优先去缓存中取isStop,发现缓存中有isStop,于是就取到了isStop=false,while循环条件(!isStop)成立。

    过了一段时间,主线程执行isStop=true,由于这个操作,缓存和主内存中的isStop都变为了true。

    但是,thread线程并不知道isStop已被主线程所修改,因为主线程在修改isStop值的时候并没有通知到各个已拥有isStop的缓存。

    于是,thread线程就继续执行着while(!isStop)无法停止。

    解决办法

    综上所述,内存可见性问题就是有多个线程同时读取同一变量,当其中任意一个线程修改其变量的值时,其他线程都无法及时得到最新值。

    内存可见性中的“内存”指的是主内存,“可见性”有两种,一种是可见,还有一种是不可见。

    可见:多个线程共享变量时,其中一个线程修改其变量的值,其他线程及时得到最新值。

    不可见:多个线程共享变量时,其中一个线程修改其变量的值,其他线程无法及时得到最新值。

    例如,上述问题中主线程和thread线程就是多个线程,isStop就是它们读取的同一变量,主线程去修改了它的值,thread线程无法及时得到最新值。

    这也说明了:主线程在某一时刻是执行写入操作的线程,thread线程在某一时刻是执行读取操作的线程。

    解决这个问题就在于只要让执行写入操作的线程将数据写完之后能够通知到其他执行读取操作的线程即可。

    请问这像什么?像不像同步?

    同步还真能解决我们的问题。同步我们知道有隐式锁synchronized和显式锁Lock,这两种锁都能解决我们的问题,下面来看看。

    Java多线程基础不好的同学可以前去阅读《“全栈2019”53篇Java多线程学习资料及总结》一章查阅相关Java多线程基础学习资料。

    隐式锁synchronized

    改写例子,在thread线程中的while循环里面加上同步代码块或调用同步方法:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    例子改写完毕。

    运行程序,执行结果:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    从运行结果来看,符合预期。程序在1秒钟之后停下来了,问题得到了解决。

    接下来把显式锁演示完了,我们再来说同步为什么能解决内存可见性问题。

    显式锁Lock

    改写例子,将while循环里面的同步代码块移除掉:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    然后,创建出显式锁Lock:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    接着,在while循环里面加锁:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    例子改写完毕。

    运行程序,执行结果:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    从运行结果来看,符合预期。程序在1秒钟之后停下来了,问题也得到了解决。

    同步为什么能够解决内存可见性问题?

    因为无论缓存中有没有变量,同步都会使线程去主线程获取变量,而不是在缓存中获取,所以线程每次取得的变量都是最新的。

    当然了,为了一个变量我们就用上同步,这代价未免也太大了吧?

    为此,Java为我们提供了解决办法:volatile关键字

    如果你只是解决内存可见性问题,volatile关键字足以。

    volatile关键字怎么用?

    请往下看。

    3.volatile关键字

    volatile关键字含义:

    表明变量必须同步地发生变化。

    volatile关键字用于修饰变量。

    下面我们就来试试volatile关键字。

    还是上一小节例子,首先将显式锁Lock对象移除掉:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    然后,将显式锁同步代码移除掉:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    接着,我们使用volatile关键字修饰isStop变量:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    例子改写完毕。

    运行程序,执行结果:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    从运行结果来看,符合预期。程序在1秒钟之后停下来了,问题同样得到了解决。

    下面,我们来通过动画感受一下加了volatile关键字之后的程序运行过程:

    “全栈2019”Java原子操作第一章:内存可见性volatile关键字解析

     

    这里简单说一下过程:

    当isStop被volatile关键字所修饰之后,每当线程需要去获取isStop变量时,都要去主内存中获取,所以在主线程修改isStop值为true时,thread线程及时读到了,于是while循环条件(!isStop)不成立,程序结束。

    本系列是Java原子操作系列,volatile关键字和下一章要介绍的比较并交换CAS技术都是Java原子操作预备知识,大家应该好好理解与体会。

    最后,希望大家可以把这个例子照着写一遍,然后再自己默写一遍,方便以后碰到类似的面试题可以轻松应对。

    祝大家编码愉快!

    GitHub

    本章程序GitHub地址:https://github.com/gorhaf/Java2019/tree/master/Thread/volatile

    总结

    • 内存可见性问题就是有多个线程同时读取同一变量,当其中任意一个线程修改其变量的值时,其他线程都无法及时得到最新值。
    • 内存可见性中的“内存”指的是主内存,“可见性”有两种,一种是可见,还有一种是不可见。
    • 可见:多个线程共享变量时,其中一个线程修改其变量的值,其他线程及时得到最新值。
    • 不可见:多个线程共享变量时,其中一个线程修改其变量的值,其他线程无法及时得到最新值。
    • 因为无论缓存中有没有变量,同步都会使线程去主线程获取变量,而不是在缓存中获取,所以线程每次取得的变量都是最新的。
    • volatile关键字含义:表明变量必须同步地发生变化。
    • volatile关键字用于修饰变量。
    • 如果你只是解决内存可见性问题,volatile关键字足以。
    展开全文
  • 内存可见性问题

    2018-09-24 21:23:35
    可以使用volatile 关键字:当多个线程调用共享数据时,可以保证内存中的数据可见;效率比锁高; 相较于synchronized 是一种较为轻量级的同步策略; 注意: 1. synchronized具有互斥,而volatile不具备;互斥...

    当多个线程操作共享数据时,彼此不可见是一个问题;

    可以使用volatile 关键字:当多个线程调用共享数据时,可以保证内存中的数据可见;效率比锁高;

    相较于synchronized 是一种较为轻量级的同步策略;

    注意:

    1.  synchronized具有互斥性,而volatile不具备;互斥性:当一个线程作用于一个对象是,另外一个线程进不来;线程互相排斥;

    2. 不能保证变量的"原子性"; 

    当程序运行时,JVM为每个线程提供一个独立的缓存提高效率;

    JVM底层会对内存进行重排序,但是使用volatile关键字后,不会进行重排序;性能会有所下降;

    public static void main(String[] args) {
            ThreadDemo demo = new ThreadDemo();
            new Thread(demo).start();
            while(true){
    //            synchronized(demo){
                    if(demo.isFlag()){
                        System.out.println("-----------");
                        break;
                    }
    //            }   
            }
        }

    class ThreadDemo implements Runnable{

        private volatile boolean flag = false;
        
        @Override
        public void run() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true;
            System.out.println("flag="+isFlag());
        }

        public boolean isFlag() {
            return flag;
        }

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

     

     

     

     

     

     

    展开全文
  • Java多线程之内存可见性

    万次阅读 热门讨论 2015-11-03 02:47:55
    1、什么是JAVA 内存模型 Java Memory Model (JAVA 内存模型)描述线程之间如何通过内存(memory)来进行交互。 具体说来, JVM中存在一个主存区(Main Memory或Java Heap Memory),对于所有线程进行共享,而每个线程...
  • 浅谈Java多线程之内存可见性

    千次阅读 2018-10-31 11:07:23
    可见性介绍: synchronized实现可见性原理: synchronized实现可见性代码: volatile实现可见性: volatile不能保证原子性: 再谈谈CPU: CPU的Cache模型: CPU缓存一致性问题: 关于内存屏障:     ...
  • 内存可见性和原子性:Synchronized和Volatile的比较

    万次阅读 多人点赞 2016-09-13 14:58:23
    Java多线程之内存可见性和原子性:Synchronized和Volatile的比较  【尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/52015707  在说明Java多线程内存可见性之前,先来简单了解...
  • 并发本来就是个有意思的问题,尤其是现在又流行这么一句话:“高帅富加机器,穷矮搓搞优化”。从这句话可以看到,无论是高帅富还是穷矮搓都需要深入理解并发编程,高帅富...JAVA内存模型 对于我们平时开发的业务应
  • 保证此变量对所有线程的可见性,这里的 “可见性” 是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。 禁止指令重排序优化。 &amp...
  • Synchronized的内存可见性

    千次阅读 2015-04-10 18:54:46
    在Java中,我们都知道关键字synchronized可以用于实现线程间的互斥,但我们却常常忘记了它还有另外一个作用,那就是确保变量在内存可见性 - 即当读写两个线程同时访问同一个变量时,synchronized用于确保写线程...
  • public class NoVisibility { private static boolean ready; private static int num;...求助各位大牛,上面的代码在-server的jvm中 无限循环,一直没想通,主线程设置ready=true,循环的线程为什么会无限循环呢?
  • 并发本来就是个有意思的问题,尤其是现在又流行这么一句话:“高帅富加机器,穷矮搓搞优化”。从这句话可以看到,无论是高帅富还是穷矮搓都需要深入理解并发编程,高帅富加多了机器,需要协调多台机器或者多个CPU对...
  • JMM内存可见性与顺序一致性模型

    千次阅读 2016-08-20 22:37:11
    首先让我们从as-if-serial语义讲起,程序执行时为提高性能,编译器和处理器常常会对指令做重排序,该语义是...编译器和处理器中为了实现as-if-serial语义,定义了一系列的重排序规则,并通过内存屏障指令实现。 内存
  • volatile关键字如何保证内存可见性

    千次阅读 2018-02-23 01:00:42
    保证内存可见性(但不保证操作的原子性)。 防止指令重排。 (一)内存可见性 JVM内存模型:主内存和线程独立的工作内存 Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的...
  • 多线程之内存可见性

    2018-12-21 19:03:51
    可见性:一个线程对共享变量值得修改,能够及时地被其他线程看到。
  • 具体说来, JVM中存在一个主存区(Main Memory或Java Heap Memory),对于所有线程进行共享,而每个线程又有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作并非...
  • 转载自 深度好文 | Java 可重入锁内存可见性分析一个习以为常的细节之前在做 ReentrantLock 相关的试验,试验本身很简单,和本文相关的简化版如下:(提示:以下代码均可左右滑动)private static ReentrantLock ...
  • 原文出处: oschina 并发本来就是个有意思的问题,尤其是现在又流行这么一句话:“高帅富加机器,穷矮搓搞优化”。从这句话可以看到,无论是高帅富还是穷矮搓都需要深入理解并发编程,高帅富加多了机器,需要...
  • Mutex和内存可见性

    千次阅读 2013-11-29 17:38:31
    介绍 POSIX线程遵守共享内存模型[1],此...内存可见性:一旦线程修改数据对象,其它线程在修改行为发生之后马上能看见此对象的新状态,如图1所示。 Mutex通常被引进作为实现原子访问的手段,但它的作用不仅仅是
  • java volatile为什么能保证内存可见性

    千次阅读 2019-03-28 00:42:49
    本文讲解为什么 volatile关键字可以让变量在任何线程都可见 计算机在运行程序时,每条指令都是在CPU中执行的,在执行过程中势必会涉及到数据的读写。我们知道程序运行的数据是存储在主存中,这时就会有一个问题,...
  • Java多线程之内存可见性和原子性:Synchronized和Volatile的比较 在说明Java多线程内存可见性之前,先来简单了解一下Java内存模型。(具体的图查阅我上一篇博客) (1)Java所有变量都存储在主内存中 (2)每个线程...
  • 多线程之内存可见性和原子性 可见性:一个线程/进程对共享变量的修改能够及时被其它的线程/进程看到 原子性:即操作不可再分(在汇编层面看为一条机器指令),比如a = 1, 和 return a 分别具有原子性, 但 “a += b...
  • 上一篇博客已经讲到了内存可见性问题,内存可见性所表现出来的问题就是失效数据,而有效规避这种问题的方法就是同步。本篇博客将告诉你具体采用哪些同步方式可以解决这类问题:加锁,volatile变量。1、 加锁与可见...
  • jmm内存可见性与CAS

    2019-09-15 16:27:03
    前言:在慕课网上学习剑指Java面试-Offer直通车时所做的笔记,供本人复习之用. ...2.3 可见性问题 2.4 指令重排序需要满足的条件 2.5 happens-before原则 2.5.1 例1 2.5.2 volatile 2.5.3 例2...
  • 什么是内存可见性

    2019-09-27 21:32:15
    什么是可见性? 一个线程修改了共享变量的值,其他线程也能看到最新修改的值。 下图是一段存在线程可见性问题的代码: 在主线程中修改两个变量的值,不一定对副线程可见,副线程有可能读取到为false的ready和为111...
  • jmm的内存可见性

    2019-07-02 10:50:05
    什么是Java内存模型中的happens-before Java内存模型JMM Java内存模型(即Java Memory Model,简称JMM)本身是一种抽象的概念, 并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括...
  • 并发编程之内存可见性一、如何保证共享变量的可见性二、从number++看原子操作三、volatile适用场合四、重排序五、as-if-serial原则六、volatiele 和synchronized比较七、64位变量(long,double) 一、如何保证共享...
  • 内存可见性 volatile保证可见性的原理是在每次访问变量时都会进行一次刷新,因此每次访问都是主内存中最新的版本。所以volatile关键字的作用之一就是保证变量修改的实时可见性。 当且仅当满足以下所有条件时,才...
  • JMM内存可见性

    2019-04-17 21:38:25
  • 代码来源 public class TestVolatile { public static void main(String[] args) throws InterruptedException { ThreadDemo threadDemo = new ThreadDemo(); new Thread(threadDemo).start();...

空空如也

1 2 3 4 5 ... 20
收藏数 245,141
精华内容 98,056
关键字:

内存可见性