第四章:对象的组合——java并发编程实战

一、设计线程安全的类

  • 找出构造对象状态的所有变量(若变量为引用类型,还包括引用对象中的域)
  • 约束状态变量的不变性条件
  • 建立对象状态的并发访问管理策略(规定了如何维护线程安全性)

1、收集同步需求(找出复合操作、多个变量遵循原子性的操作等)

2、依赖状态的操作(找出操作是否基于先验条件,例:取出当队列不为空)

3、状态的所有权(对象被哪些线程所有,哪些线程可以操作对象)

二、实例封闭

将数据封装在对象内部,可以将数据的访问限制在对象的方法上,确保简单正确的持有锁。(因为无需观察整个程序,只需检查当前类)

Java提供包装器对ArrayList、HashMap等容器对象提供线程安全保护

1、Java监视器模式:把对象的所有可变状态封装起来,并使用对象的内置锁保护

使用私有锁而不是内置锁的优点:(private final Object myLock = new Object();)

  • 私有锁可以将锁封装起来,客户代码无法得到锁
  • 客户可以通过公有方法来访问锁,以便参与到同步策略中去。

2、实例:基于监视器模式的车辆追踪

MutablePoint不一定是线程安全的,但该类一定是线程安全的,因为它包含的Map对象与Map中的Point对象都未曾发布,并且满足实例封闭。

三、线程安全性的委托

通过多个线程安全的类组成的类不一定是线程安全的

委托:通过委托类的线程安全性判断被委托类的线程安全性

1、委托给单个线程安全状态变量可以保证线程安全性

2、委托给多个相互独立的线程安全状态变量可以保证线程安全性

3、如果类包含多个线程安全状态变量的符合操作,则无法保证线程安全性,可以通过加锁机制保证

4、发布:如果一个状态变量是线程安全的,并且没有不变性条件约束它(例:大于0),在变量操作上没有不允许的状态转换,则可以安全发布

5、安全发布底层状态的线程安全类

 1 @ThreadSafe
 2 public class PublishingVehicleTracker {
 3     private final Map<String, SafePoint> locations;
 4     private final Map<String, SafePoint> unmodifiableMap;
 5
 6     public PublishingVehicleTracker(Map<String, SafePoint> locations) {
 7         this.locations = new ConcurrentHashMap<String, SafePoint>(locations);
 8         this.unmodifiableMap = Collections.unmodifiableMap(this.locations);
 9     }
10
11     public Map<String, SafePoint> getLocations() {
12         return unmodifiableMap;
13     }
14
15     public SafePoint getLocation(String id) {
16         return locations.get(id);
17     }
18
19     public void setLocation(String id, int x, int y) {
20         if (!locations.containsKey(id))
21             throw new IllegalArgumentException("invalid vehicle name: " + id);
22         locations.get(id).set(x, y);
23     }
24 }

四、现有的线程安全类中添加功能

例:在Vector中添加”若没有则添加“功能,可以使用拓展的办法,BetterVector继承至Vector并对该符合操作通过同步机制增加原子性

1、客户端加锁机制

  使用某个对象的代码时必须使用该对象本身用于保护其状态的锁,不推荐(同步的实现被分到两个不相关的类中)

当没有使用同一个锁,不足以提供线程安全保护:

2、组合

ImprovedList将List的操作委托给底层的list实例来操作,并通过自身的内置锁增加一层额外的加锁,同时添加了新的同步方法。

五、将同步策略文档化

时间: 2024-10-15 13:24:04

第四章:对象的组合——java并发编程实战的相关文章

第三章:对象的共享——java并发编程实战

我们不仅仅希望防止某个线程使用某个状态时,另一个线程在修改它:我们还希望某个线程修改了某个状态后,其他线程能够看到状态的变化. 一.可见性 重排序:在没有同步的情况下,编译器.处理器可能对代码的执行顺序进行一些调整 例如如下代码,由于没有使用同步机制,读线程可能看不见ready的修改,而一直循环下去:也可能由于重排序,看到了ready的修改number仍没修改而输出0 1.失效数据 在缺少同步的程序中产生错误的结果的一种情况.造成程序的不确定性. 2.非原子的64位操作 即使是失效数据也是程序过

第二章:线程安全性——java并发编程实战

一个对象是否需要是线程安全的取决于它是否被多个线程访问. 当多个线程访问同一个可变状态量时如果没有使用正确的同步规则,就有可能出错.解决办法: 不在线程之间共享该变量 将状态变量修改为不可变的 在访问状态变量时使用同步机制 完全由线程安全类构造的程序也不一定是线程安全的,线程安全类中也可以包含非线程安全的类 一.什么是线程安全性 线程安全是指多个线程在访问一个类时,如果不需要额外的同步,这个类的行为仍然是正确的.(因为线程安全类中封装了必要的同步代码) 一个无状态的类是线程安全的.无状态类是指不

JAVA并发编程实战 读书笔记(二)对象的共享

<java并发编程实战>读书摘要 birdhack 2015年1月2日 对象的共享 JAVA并发编程实战读书笔记 我们已经知道了同步代码块和同步方法可以确保以原子的方式执行操作,但一种常见的误解是,认为关键之synchronized只能用于实现原子性或者确定临界区.同步还有另一个重要的方面:内存可见性. 1.可见性 为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程

java并发编程实战学习笔记之对象的组合与基础构建模块

第四章 对象的组合 4.1 构建安全的类 4.2 实例封闭 @ThreadSafe public class PersonSet {     @GuardedBy("this") private final Set<Person> mySet = new HashSet<Person>();     public synchronized void addPerson(Person p) {         mySet.add(p);     }     pub

《Java并发编程实战》第三章 对象的共享 读书笔记

一.可见性 什么是可见性? Java线程安全须要防止某个线程正在使用对象状态而还有一个线程在同一时候改动该状态,并且须要确保当一个线程改动了对象的状态后,其它线程能够看到发生的状态变化. 后者就是可见性的描写叙述即多线程能够实时获取其它线程改动后的状态. *** 待补充   两个工人同一时候记录生产产品总数问题 1. 失效数据 可见性出现故障就是其它线程没有获取到改动后的状态,更直观的描写叙述就是其它线程获取到的数据是失效数据. 2. 非原子64位操作 3. 加锁与可见性 比如在一个变量的读取与

《Java并发编程实战》第十一章 性能与可伸缩性 读书笔记

造成开销的操作包括: 1. 线程之间的协调(例如:锁.触发信号以及内存同步等) 2. 增加的上下文切换 3. 线程的创建和销毁 4. 线程的调度 一.对性能的思考 1 性能与可伸缩性 运行速度涉及以下两个指标: 某个指定的任务单元需要"多快"才能处理完成.计算资源一定的情况下,能完成"多少"工作. 可伸缩性: 当增加计算资源时(例如:CPU.内存.存储容器或I/O带宽),程序的吞吐量或者处理能力能相应地增加. 2 评估各种性能权衡因素 避免不成熟的优化.首先使程序正

《Java并发编程实战》第十六章 Java内存模型 读书笔记

Java内存模型是保障多线程安全的根基,这里仅仅是认识型的理解总结并未深入研究. 一.什么是内存模型,为什么需要它 Java内存模型(Java Memory Model)并发相关的安全发布,同步策略的规范.一致性等都来自于JMM. 1 平台的内存模型 在架构定义的内存模型中将告诉应用程序可以从内存系统中获得怎样的保证,此外还定义了一些特殊的指令(称为内存栅栏或栅栏),当需要共享数据时,这些指令就能实现额外的存储协调保证. JVM通过在适当的位置上插入内存栅栏来屏蔽在JVM与底层平台内存模型之间的

《Java并发编程实战》第十五章 原子变量与非阻塞同步机制 读书笔记

一.锁的劣势 锁定后如果未释放,再次请求锁时会造成阻塞,多线程调度通常遇到阻塞会进行上下文切换,造成更多的开销. 在挂起与恢复线程等过程中存在着很大的开销,并且通常存在着较长时间的中断. 锁可能导致优先级反转,即使较高优先级的线程可以抢先执行,但仍然需要等待锁被释放,从而导致它的优先级会降至低优先级线程的级别. 二.硬件对并发的支持 处理器填写了一些特殊指令,例如:比较并交换.关联加载/条件存储. 1 比较并交换 CAS的含义是:"我认为V的值应该为A,如果是,那么将V的值更新为B,否则不需要修

《Java并发编程实战》第二章 线程安全性 读书笔记

一.什么是线程安全性 编写线程安全的代码 核心在于要对状态访问操作进行管理. 共享,可变的状态的访问 - 前者表示多个线程访问, 后者声明周期内发生改变. 线程安全性 核心概念是正确性.某个类的行为与其规范完全一致. 多个线程同时操作共享的变量,造成线程安全性问题. * 编写线程安全性代码的三种方法: 不在线程之间共享该状态变量 将状态变量修改为不可变的变量 在访问状态变量时使用同步 Java同步机制工具: synchronized volatile类型变量 显示锁(Explicit Lock