美文网首页
三、线程可见性(对象的共享问题)

三、线程可见性(对象的共享问题)

作者: RainySpring | 来源:发表于2020-04-18 23:59 被阅读0次

线程可见性和线程安全性有什么关联?
我们不仅希望防止某个线程正在使用对象状态而另一个线程在同时修改状态,而且还希望确保当一个线程修改状态后,其他线程能够看到发生的状态变化

概念层面的可见性

  1. 什么是线程间的可见性?
    一个线程对共享变量值的修改,能够及时的被其他线程看到。

  2. 什么是共享变量?
    如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。

  3. 什么是java内存模型?(Java Memory Model,简称JMM)
    JMM描述了java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。
    规则1:
    1> 所有的变量都存储在主内存中
    2> 每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)
    规则2:
    1> 线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写
    2> 不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量的传递需要通过主内存来完成

    image.png
    共享变量可见性实现的原理:
    线程1对共享变量的修改要想被线程2及时看到,必须经过如下2个步骤:
    1> 把工作内存1中更新过的共享变量刷新到主内存中
    2> 将主内存中最新的共享变量的值更新到工作内存2中

java语言层面支持的可见性实现方式有以下两种:
1> synchronized
2> volatile

注意:synchronized实现可见性以及原子性,
而volatile只能保证变量的可见性,就是不做下面互斥代码过程的第2步操作,没有锁且不会清空工作内存;只发挥了第5步的作用:及时将在工作内存中更新的变量刷到主内存中去。

JMM关于synchronized的两条规定:
1> 线程解锁前(退出synchronized代码块之前),必须把共享变量的最新值刷新到主内存中,也就是说线程退出synchronized代码块值后,主内存中保存的共享变量的值已经是最新的了
2> 线程加锁时(进入synchronized代码块之后),将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁与解锁需要是同一把锁)
两者结合:线程解锁前对共享变量的修改在下次加锁时对其他线程可见
根据以上推出线程执行互斥代码的过程:
1> 获得互斥锁(进入synchronized代码块)
2> 清空工作内存
3> 从主内存拷贝变量的最新副本到工作内存
4> 执行代码
5> 将更改后的共享变量的值刷新到主内存
6> 释放互斥锁(退出synchronized代码块)

4. 什么是指令重排序?
代码书写的顺序与实际执行的顺序不同,指令重排序是编译器或处理器为了提高程序性能而做的优化(有些代码翻译成机器指令之后,如果进行一个重排序,那可能重排序之后的顺序更加符合CPU执行的特点,这样就可以最大限度发挥CPU的性能)
1> 编译器优化的重排序(编译器)
2> 指令级并行重排序(处理器优化)
3> 内存系统的重排序(处理器优化)

5. 什么是as-if-serial语义?
无论如何重排序,程序执行的结果应该与代码顺序执行的结果一致(java编译器、运行时和处理器都会保证java在单线程下遵循as-if-serial语义)
int num1=1;
int num2=2;
int sum=num1+num2;
单线程:第1、2行的顺序可以重排,但第3行不能

6. ReentrantLock锁
除了用synchronized解决共享变量多线程问题,还可以使用ReentrantLock锁,具体区别我们以后再说。

ReentrantLock lock = new ReentrantLock();
    lock.lock();
    //lock.tryLock(timeout, unit); 设置锁时间
    //业务代码
    lock.unlock();

7. 分布式系统如何实现可见性(分布式锁)?
redis、zk、Chubby

相关文章

  • 三、线程可见性(对象的共享问题)

    线程可见性和线程安全性有什么关联?我们不仅希望防止某个线程正在使用对象状态而另一个线程在同时修改状态,而且还希望确...

  • Java并发编程实战读书笔记

    第二章 线程安全性 持有锁时间过长会带来活跃性和性能问题。 第三章 对象的共享 可见性 不同线程的可见性导致在竞态...

  • 02|Java内存模型

    可见性、原子性、有序性是并发问题的三个关键因素。 可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到。 可...

  • 【Java进阶】并发编程

    . 概述 三种性质 可见性:一个线程对共享变量的修改,另一个线程能立刻看到。缓存可导致可见性问题。 原子性:一个或...

  • Java并发

    本文回顾并发知识,划出关键部分, 并发基础 “共享”、“可变“、“可重入”,线程之间对象“可见性”是并发的基础。 ...

  • 《JAVA并发编程实战》读书笔记----持续更新

    第三章 对象的共享 3.1可见性 可见性:在我看来,可见性的的意思是操作可见性;就是共享的可变的对象的所有操作后的...

  • 【java并发编程实战读书总结3】什么是内存可见性

    可见性 什么是可见性? 一个线程修改了共享变量的值,其他线程也能看到最新修改的值 。 下图是一段存在线程可见性问题...

  • 源码修炼笔记之ThreadLocal详解

    多线程线程安全的根源就是“共享”,即多个线程操作共享变量会引起可见性、原子性和顺序性的问题。解决线程安全首先我们想...

  • Volatile原理总结

    内存可见性 内存可见性相关概念:线程对共享变量修改的可见性。当一个线程修改了共享变量的值,其他线程能够立刻得知这个...

  • 6.volatile:可见性

    什么是可见性? 可见性就是,多线程环境中,对共享变量的修改对于其他线程是否立即可见的问题。举个例子: 子线程,1s...

网友评论

      本文标题:三、线程可见性(对象的共享问题)

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