Java并发编程实战:第三章读书笔记

第三章 对象的共享

摘要: 本章主要介绍了

线程安全问题基本都是由共享状态的非同步导致的。

1. 可见性, 所谓可见性其实是一个相对复杂的概念。我理解的可见性就是某一个操作的结果对另外的操作是可见的这就是可见性。

正是因为可见性的不可预见性,所以当我们的代码在没有同步的情况下,经过编译器、处理器以及运行时等都有可能对操作的执行顺序进行调整。

2. 失效数据,这里首先有一个概念就是JMM(Java memory model)

结合刚才的可见性来解释什么是失效数据,当线程A对数据X进行了改变的时候,X的改变只存在于线程A的工作内存中,那么到线程A对X的修改被写入到主存之前的这段时间里,数据X对其他的线程来讲就是失效数据。更好理解的叫法我觉得是过时的数据。

3. 如何保证可见性-通常是两种方式① 对代码块进行加锁处理 ② 使用volatile修饰变量。

在这里向大家推荐一本小书 一共70多页叫做: 《深入理解Java内存模型》(程晓明) 这本书里面的happens-before原则。以及Synchronized volatile 的相关讲解及其他内容 都值得多次浏览 对于大家理解多进程会有很大的帮助。

4. 安全的发布对象

保证对象安全的构造初始化过程: 保证在构造过程中,对象不会逃逸。

开头说明导致多线程问题的罪魁祸首就是可变状态(变量)的共享,那么解决问题的最佳手段自然就是不共享。 其实这也是为什么有些初级程序员虽然并没有刻意的将多线程考虑在内,但并没有出现线程安全问题的原因。就是因为我们大多数的代码使用到的可变的状态基本都是被封装在了方法 类 或其他地方 他是线程封闭的不会被其他线程共享。

那么实现线程封闭的方法书中给了三种: Ad-hoc线程封闭、Threa-local类、栈封闭。

除了将变量封闭之外,还有另外一种解决线程问题的方法,那就是保证状态的不可变性。满足不变性的对象有三个条件:

    1. 对象被创建或者第一次初始化后,其状态就不能再被修改。

    2. 对象的所有域都是final类型的。

    3. 对象时正确创建的。

书中介绍了安全的发布对象的几种模式:

    1. 在静态初始化函数中初始化一个对象引用。

    2. 将对象的引用保存到volatile类型的域或者AtomicReferance对象中。

    3. 将对象的引用保存到某个正确构造对象的final域中去。

    4. 讲对象的引用保存到一个有所保护的域中。

除了真实不可变对象外 还有一个概念叫做事实不可变对象。就是说虽然某些对象看起来是可变的,但是通常我们不会在初始化后再去改变的对象叫做事实不可变对象。例如Java中的Date对象。

5. 可变对象

本书给了在并发程序中使用和共享可变对象时,采取的策略:

    1. 线程封闭

    2. 只读共享

    3. 线程安全共享,对象在其内部实现同步,因此多个线程可以通过对象的公有接口来进行访问

    4. 保护对象,被保护的对象只能通过持有特定的锁才能访问。

3.4的区别在于 3是使用的对象的内部使用同步机制,4则表示我们在使用对象时实现同步。

总结: 本书的前4章主要介绍的是一些感念的东西可能相对晦涩,不过这是学习并发编程的必经之路,理解了这些概念才能明白后面的代码为什么这样写。那么本章作者主要给出了导致线程安全问题的原因以及通常情况下解决他们的策略。

猜你喜欢

转载自blog.csdn.net/lcn_2017/article/details/81272475