java并发编程实战阅读笔记(第四章)对象的组合
来源:互联网 发布:淘宝上的装修付款方式 编辑:程序博客网 时间:2024/05/22 16:38
一、设计线程安全的类
在设计线程安全类的过程中,需要包含三个步骤:
1)找出构成对象状态的所有变量。
2)找出约束状态变量的不变形条件。
3)建立对象状态的并发访问管理策略。
对象的域:是指对象中的变量。
对象的状态:如果对象中的所有域都是基本类型的变量,那么这些域将构成对象的全部状态。如果对象中引用了其他对象,那么该对象的状态将包含被引用对象的域。
收集同步需求
如果不了解对象的不变性条件与后验条件,那么就不能确保线程安全性。要满足在状态变量的有效值或状态转换上的各种约束条件,就需要借助原子性和封装性。
说的更简略些是Java线程安全问题都是因为共享变量,共享变量后会因为多个线程同时修改导致不正确的问题,所以收集一共有多少处会涉及到这些需要同步的变量,只有收集说有可能出问题的因素基于此之上保证所有元素线程安全也才能保证程序是线程安全的。
依赖状态的操作
在某些对象的方法中还包含一些基于状态的先验条件,如删除前的非空判断,这样的操作就被称为依赖状态的操作。要想实现某个等待先验条件为真时才执行的操作,一种简单的方法是通过现有库中的类,如阻塞队列Blocking Queue或者信号量Semaphore来实现依赖状态的行为。
状态的所有权
单独一个基本对象比较保证其安全性,但是如果是包含对象的集合(容器类 例如:ArrayList),容器类通常表现出一种“所有权分离”的形式。
即使用线程安全的容器类(Collections.synchronizedList(List)),也只能保证容器相关的操作是线程安全的,如果发布了可变对象的引用,就不会拥有独占的控制权。(非线程安全)
二、实例封闭
将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程在访问数据时总能持有正确的锁。
封闭机制更易于构造线程安全的类,因为当封闭类的状态时,在分析类的线程安全性时就无须检查整个程序。
Java监听器模式
遵循java监视器模式的对象会把对象的所有可变状态都封装起来,并由对象自己的内置锁来保护。
示例:
public class Counter { private long value = 0; public synchronized long getValue(){ return this.value; } public synchronized long increment(){ if(value == Long.MAX_VALUE){ throw new IllegalStateException("counter overflow"); } return ++value; }}
或者:
public class Counter { private Long value = 0l; public long getValue(){ synchronized (value) { return this.value; } } public long increment(){ synchronized (value) { if(value == Long.MAX_VALUE){ throw new IllegalStateException("counter overflow"); } return ++value; } }}
使用私有的锁对象而不是对象的内置锁,有许多优点,私有的锁对象可以将锁封装起来,使客户端代码无法获取到锁,以便参与到它的同步策略中,避免产生活跃性问题。
synchronized为什么不能修饰基本数据类型?
因为基本数据类型是放在栈里面的,栈数据是可共享的,所以不能加synchronized。
三、线程安全性的委托
通过多个线程安全的类组成的类不一定是线程安全的
1、委托给单个线程安全状态变量可以保证线程安全性
2、委托给多个相互独立的线程安全状态变量可以保证线程安全性(完全独立,不存在依赖状态的操作)
3、如果类包含多个线程安全状态变量的符合操作,则无法保证线程安全性,可以通过加锁机制保证
4、安全发布底层状态的线程安全类
concurrentHashMap
copyOnWriteArrayList
四、现有的线程安全类中添加功能
1、客户端加锁机制
使用某个对象的代码时必须使用该对象本身用于保护其状态的锁,不推荐(同步的实现被分到两个不相关的类中)
在客户端加锁,但要确保使加锁对象在实现客户端加锁或者外部加锁时使用同一个锁。
@ThreadSafe public class ListHelper<E>{ public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public boolean putIfAbsent(E x){ synchronized(list){//使List在实现客户端加锁或者外部加锁时使用同一个锁 boolean absent = !list.contains(x); if(absent) list.add(x); return absent; } } }
另外一个更好的方式是使用组合
@ThreadSafe public class ImprovedList<T> implements List<T>{ private final List<T> list; public ImprovedList(List<T> list){ this.list = list; } public synchronized boolean putIfAbsent(T x){ boolean contains = list.contains(x); if(!contains) list.add(x); return !contains; } }
将同步策略文档化
在文档中说明客户代码需要了解的线程安全性保证,以及代码维护人员需要了解的同步策略。
- java并发编程实战阅读笔记(第四章)对象的组合
- 《Java并发编程实战》第四章 对象的组合 读书笔记
- Java并发编程实战第四章对象的组合
- Java并发编程实战(学习笔记三 第四章 对象的组合)
- Java并发编程实战笔记(三):对象的组合
- java并发编程实战:组合对象笔记
- Java并发编程实战笔记(3)-对象的组合
- java并发编程实战阅读笔记(第三章)对象的共享
- java并发编程实战-对象的组合
- [Java 并发] Java并发编程实践 思维导图 - 第四章 对象的组合
- java并发编程实践-第四章-组合对象
- java并发编程实战学习笔记之对象的组合与基础构建模块
- 重温《并发编程实战》---对象的组合
- 关于《Java并发编程实战》 -- 第一部分的阅读笔记
- 关于《Java并发编程实战》 -- 第二部分的阅读笔记
- 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象
- 《Java并发编程实战》笔记--共享对象
- Java并发编程实战笔记(二):对象的共享
- SpringMVC+Spring阅读笔记——SpringMVC概览
- 1145.cn 百度MIP适配实例
- Java基础--基本数据类型(整型)
- MYSQL添加远程用户或允许远程访问三种方法
- date命令修改linux系统时间
- java并发编程实战阅读笔记(第四章)对象的组合
- IOS开发之static变量
- 懒加载
- Java-- hashcode 和 equals
- [leetcode:python] 2.Add Two Numbers
- jQuery常用方法
- poj 2279 杨氏矩阵,钩子公式
- mini usb 接口定义 5针usb接口定义图
- 像素鸟的飞行_02