《java并发编程实战》读书笔记3--对象的组合
希望将一些现有的线程安全组件组合为更大规模的组件或程序
设计线程安全的类

如果对象中所有的域是基本类型变量,那么这些域将构成对象的全部状态。例如,LinkedList的状态就包括该链表中所有节点对象的状态。要确保线程的安全性,就需要确保它的不变性条件不会在并发访问的情况下被破坏。
实例封闭
当一个对象被封装到另一个对象中时,能够访问被封装对象的所有代码路径都是已知的。通过将封闭机制与合适的加锁策略结合起来,可以确保以线程安全的方式来使用非线程安全的对象。被封闭对象一定不能超出它们既定的作用域。来个例子

如果Person类是可变的,那么在访问从PersonSet中获得的Person对象时,还需要额外的同步。在java平台的类库中有很多线程封闭的实例,其中有些类的唯一用途是将非线程安全的类转化为线程安全的类。一些基本容器类并非线程安全的,例如ArrayList和Hash,但类库提供了包装器工厂方法(例如Collections.synchronizedList及其类似方法),使得这些线程非安全的类可以在多线程环境中安全地使用。这些工厂方法通过“装饰器”模式将容器类封装在一个同步的包装器对象中,而包装器能将接口中的方法都实现为同步方法,并将调用请求转发到底层的容器对象上。只要包装器对象拥有对底层容器对象的唯一引用,那么他就是线程安全的。
java监视器模式
把所有可变状态都封装起来,并由对象自己的内置锁来保护。如:


看到了有意思的部分了:

使用私有锁而不是对象的内置锁(或任何其他可通过公有方式访问的锁), 有许多优点。私有的锁对象可以将锁封装起来,是客户代码无法得到锁,但客户代码可以通过公有方法来获得锁。这是书上的原话,然而看不懂....。首先要搞明白的是私有锁和内置锁的区别,在网上看到一篇不错的博文:http://www.jb51.net/article/56440.htm。
1. 类锁:在代码中的方法上加了static和synchronized的锁,或者synchronized(xxx.class)的代码段。
2.对象锁:在代码中的方法上加了synchronized的锁,或者synchronized(this)的代码段。
3.私有锁:在类内部声明一个私有属性如private Object lock,在需要加锁的代码段synchronized(lock)。
4.内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。
看来内置锁和对象锁是一回事了,只不过角度不同定义自然不一样。
示例:车辆追踪
一个用于调度车辆的“车辆追踪器”,例如出租车,警车,货车等。首先使用监视器模式来构建车辆追踪器,然后在尝试放宽某些封装性需求同时又保持线程安全性。

执行更新操作的线程通过从GPS设备上获取的数据或者调度员从GUI界面上输入的数据来修改车辆的位置

视图线程与执行更新操作的线程将并发地访问数据模型,因此该模型必须是线程安全的,下面的程序给出了一个基于java监视器模式实现的“车辆追踪器”,其中使用了程序清单4-5中的MutablePoint来表示车辆的位置。


虽然类MutablePoint不是线程安全的,但追踪器类是线程安全的。它所包含的Map对象和可变的Ponit对象都未曾发布,当需要返回车辆的位置时,通过MutablePoint拷贝构造函数或者deepCopy方法来复制正确值,从而生成一个新的Map对象,并且该对象中的值与原有Map对象中的key和value值都相同。
线程安全性的委托
示例:基于委托的车辆追踪器
构造一个委托给线程安全类的车辆追踪器。将车辆的位置保存到一个Map对象中,因此首先要实现一个线程安全的Map类ConcurrentHashMap。还可以用一个不可变的类Point来代替MutablePoint以保存位置, 


如果使用最初的MutablePoint类而不是Point类就会破坏封装性,因为getLocations会发布一个指向可变状态的引用。这里我对监视器模式和委托之间的区别的理解是:监视器将所有可变状态封装,对这些状态的操作利用内置锁保护起来。而委托模式则是将这些状态的安全性委托给一些线程安全的容器来保护。上面的代码还有一点要注意的是:getLocations返回的是一个不可修改但却实时的车辆位置视图。

独立的状态变量
将线程的安全性委托给多个状态变量。只要这些变量是彼此独立的。

当委托失效时
状态变量之间存在着某些不变性条件,如:


此时仅靠委托机制并不足以实现线程安全性,这个类必须提供自己的加锁机制。
发布底层的状态变量

示例:发布状态的车辆追踪器
在这个版本中发布底层的可变状态。


在现有的线程安全类中添加功能
简而言之就是利用java所提供的安全类库,再添加我们自己的类,来确保我们要实现的程序功能的线程安全性。
客户端加锁机制


参考:https://www.cnblogs.com/yaowen/p/5983136.html
组合
当为现有的类添加一个原子操作时,有一种更好的方法:组合。

使用了java监视器模式来封装了现有的List,只要在类中拥有指向底层List的唯一外部引用,就能确保线程安全性。(注意这里的底层List实例是私有不可变的)
心得:这章的主要内容是当多个对象组合在一起时如何确保其线程安全性。感觉这章真的是很抽象,说了很多理论性的东西,现在还是有很多不清楚,不明白的地方,还是得靠多实践才能加深理解。
《java并发编程实战》读书笔记3--对象的组合的更多相关文章
- Java并发编程实战 读书笔记(一)
最近在看多线程经典书籍Java并发变成实战,很多概念有疑惑,虽然工作中很少用到多线程,但觉得还是自己太弱了.加油.记一些随笔.下面简单介绍一下线程. 一 线程与进程 进程与线程的解释 个人觉 ...
- Java并发编程实战 读书笔记(二)
关于发布和逸出 并发编程实践中,this引用逃逸("this"escape)是指对象还没有构造完成,它的this引用就被发布出去了.这是危及到线程安全的,因为其他线程有可能通过这个 ...
- 【JAVA并发编程实战】2、对象的组合
1. 设计线程安全的类 1.找出构成对象状态的所有变量 2.找出约束状态变量的不变性条件 3.建立对象状态的并发访问管理策略 package cn.xf.cp.ch04; /** * *功能:JAVA ...
- Java并发编程实战 第4章 对象的组合
Java监视器模式 java监视器模式就是在将共享的数据封装在一个类里面,然后然后所有访问或者修改这些数据的方法都标注为synchronize. 车辆追踪模拟: 使用监视器模式: CarTracker ...
- 《java并发编程实战》笔记
<java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为: Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...
- Java多线程编程实战读书笔记(一)
多线程的基础概念本人在学习多线程的时候发现一本书——java多线程编程实战指南.整理了一下书中的概念制作成了思维导图的形式.按照书中的章节整理,并添加一些个人的理解.
- 读书笔记-----Java并发编程实战(二)对象的共享
public class NoVisibility{ private static boolean ready; private static int number; private static c ...
- Java并发编程实践读书笔记(1)线程安全性和对象的共享
2.线程的安全性 2.1什么是线程安全 在多个线程访问的时候,程序还能"正确",那就是线程安全的. 无状态(可以理解为没有字段的类)的对象一定是线程安全的. 2.2 原子性 典型的 ...
- Java并发编程艺术读书笔记
1.多线程在CPU切换过程中,由于需要保存线程之前状态和加载新线程状态,成为上下文切换,上下文切换会造成消耗系统内存.所以,可合理控制线程数量. 如何控制: (1)使用ps -ef|grep appn ...
- Java并发编程实践读书笔记(2)多线程基础组件
同步容器 同步容器是指那些对所有的操作都进行加锁(synchronize)的容器.比如Vector.HashTable和Collections.synchronizedXXX返回系列对象: 可以看到, ...
随机推荐
- POJ.3172 Scales (DFS)
POJ.3172 Scales (DFS) 题意分析 一开始没看数据范围,上来直接01背包写的.RE后看数据范围吓死了.然后写了个2^1000的DFS,妥妥的T. 后来想到了预处理前缀和的方法.细节以 ...
- 第一章 深入web请求过程
B/S架构的的好处: 客户端使用统一的浏览器(browser).由于浏览器的统一性,它不需要特殊的配置和网络连接,有效的屏蔽了不同服务提供商提供给用户使用服务的差异性.另外一点是浏览器的交互特性使得用 ...
- Log4J使用实例---日志进行邮件发送或是存入数据库
部分转摘:http://blog.csdn.net/azhao_dn/article/details/9118667 1.根类别(在类别层次结构的顶部,即全局性的日志级别) 配置根Logger,其语法 ...
- Http字段含义
转载自:http://blog.csdn.net/sand_ant/article/details/10503579 一.request请求Header简介 Accept:--客户机支持的类型 Acc ...
- [洛谷P3444] [POI2006]ORK-Ploughing
洛谷题目链接[POI2006]ORK-Ploughing 题目描述 Byteasar, the farmer, wants to plough his rectangular field. He ca ...
- [洛谷P3628] [APIO2010]特别行动队
洛谷题目链接:[APIO2010]特别行动队 题目描述 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 \(n\) 编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特别行动 ...
- c# “XXX::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。
症状描述如下: 如果将一个委托作为函数指针从托管代码封送到非托管代码,并且在对该委托进行垃圾回收后对该函数指针发出了一个回调,则将激活 callbackOnCollectedDelegate 托管调试 ...
- flask-login源码梳理
- C# 如何用多字符分割字符串
用单字符分割字符串大家应该很熟悉,例如: string source = "dfd^Afdf^AAAAAA^Adfdf"; var list= source.Split('A'); ...
- 通过.NET客户端异步调用Web API(C#)
在学习Web API的基础课程 Calling a Web API From a .NET Client (C#) 中,作者介绍了如何客户端调用WEB API,并给了示例代码. 但是,那些代码并不是非 ...