Java并发编程实战 第一部分 基础知识(三)对象的组合

Myth丶恋晨 2024-04-18 19:39 124阅读 0赞

对象的组合

不希望每一次内存访问都进行分析以确保线程是线程安全的,而是希望将一些现有的线程安全组件,组合为更大规模的组件或程序。

设计线程安全的类

在设计线程安全类的过程中,需要包含以下三个基本要素:

  1. 找出构成对象状态的所有变量。
  2. 找出约束状态变量的不变性条件。
  3. 建立对象状态的并发访问管理策略。

要分析对象的状态,首先从对象的域开始。如果对象中所有的域都是基本类型的变量,那么这些域将构成对象的全部状态。

如下代码,使用Java监视器模式的线程安全计数器

  1. public class Counter {
  2. private long value = 0;
  3. public synchronized long getValue(){
  4. return value;
  5. }
  6. public synchronized long increment(){
  7. if (value == Long.MAX_VALUE)
  8. throw new IllegalStateException("counter overflow");
  9. return ++value;
  10. }
  11. }

在该代码中,Counter中只有一个域value,因此这个value就是Counter的全部状态。

要确保类的线程安全性,就需要确保它的不变性条件不会再并发访问的情况下被破坏,这就需要对其状态进行推断。对象与变量都有一个状态空间,即所有可能的取值。状态空间越小,越容易判断线程的状态。final类型的域使用得越多,就越能简化对象可能状态得分析过程。

为了防止多线程在并发访问同一个对象时产生得相互干扰,这些对象应该要么是线程安全的对象,要么是事实不可变的对象,或者由锁来保护的对象。

实例封闭

如果某对象不是线程安全的,那么可以通过多种技术使其在多线程程序中安全地使用。你可以确保该对象只能由单个线程访问(线程封闭),或通过一个锁来保护对该对象地所有访问。

将数据封装在对象内部,可以将数据地访问限制在对象地方法上,从而更容易确保线程在访问数据时总能持有正确地锁。

被封闭对象一定不能超出它们既定地作用域。对象可以封闭在类地一个实例(作为类的一个私有成员)中,或者封闭在某个作用域内(作为一个局部变量),再或者封闭在线程内(在某个线程中将对象从一个方法传递到另一个方法,而不是在多个线程之间共享该对象)。

如下代码,PersonSet的状态由HashSet来管理的,而HashSet是非线程安全的。由于myset是私有的且不会逸出,因此HashSet被封闭在PersonSet中。唯一能访问的mySet的代码路径是addPerson域containsPerson,在执行它们时都要获取PersonSet的锁。PersonSet的状态完全由它的内置锁保护,因此PersonSet是一个线程安全的类。

  1. import java.util.HashSet;
  2. import java.util.Set;
  3. /**
  4. * 通过线程封闭机制来确保线程安全
  5. */
  6. public class PersonSet {
  7. private final Set<Person> mySet = new HashSet<Person>();
  8. public synchronized void addPerson(Person p){
  9. mySet.add(p);
  10. }
  11. public synchronized boolean containsPerson(Person p){
  12. return mySet.contains(p);
  13. }
  14. }
  15. /**
  16. * 如果Person类是可变得,那么从PersonSet中获得的Person对象时,还需要额外的同步。
  17. * 要想安全的使用Person,方法就是让Person成为一个线程安全的类。
  18. * 也可以使用锁来保护Person对象,确保访问之前已获得正确的锁
  19. */
  20. class Person{
  21. }

实例封闭是构成线程安全类的一个最简单方式,它还使得在锁策略的选择上拥有了更多的灵活性。

封闭机制更易于构造线程安全的类,因为当封闭类的状态时,在分析类的线程安全性时就无须检查整个程序。

通过一个私有锁来保护状态,如下代码

  1. public class PrivateLock {
  2. private final Object myLock = new Object();
  3. //@GuardedBy("muLock") Method method;
  4. void someMethod(){
  5. synchronized (myLock){
  6. //修改Method的状态
  7. }
  8. }
  9. }

车辆追踪(监视器模式)
实战详情查看 https://www.cnblogs.com/blueSkyline/p/9096725.html

发表评论

表情:
评论列表 (有 0 条评论,124人围观)

还没有评论,来说两句吧...

相关阅读