[Java并发编程实战] 第4章 对象的组合

设计线程安全的类
  • 过程包含三个基本要素:

    • 找出构成对象状态的所有变量
    • 找出约束状态变量的不变性条件
    • 建立对象状态的并发管理策略
  • 同步策略:如何在不违背对象不变条件或后验条件的情况下对其状态的访问操作进行协同

  • 如果在某个操作中包含有基于状态的先验条件,那么这个操作就称为依赖状态的操作

实例封闭
  • 将对象封装在类的一个实例(作为类的一个私有成员)中,或者封闭在某个作用域内(作为局部变量),再或者封闭在线程内(在某个线程中将对象从一个方法传递到另一个方法,而不是在多个线程之间共享该对象)

  • HahSet不是线程安全的

  • 只要包装器对象拥有对底层容器对象的唯一引用(即把底层容器对象封闭在包装器中),那么它就是线程安全的

  • Java监视器模式:Vector/Hashtable,把对象的所有可变状态都封装起来,并由对象自己的内置锁来保护

  • 通过在返回客户代码之前复制可变的数据来维持线程安全性,所以可能出现性能问题

线程安全性的委托
  • ConcurrentHashMap/CopyOnWriteArrayList是线程安全的

  • 如果某个类有复合操作,那么仅靠委托不足以实现线程安全性,这种情况下,这个类必须提供自己的加锁机制保证这些复合操作都是原子操作,除非整个复合操作都可以委托给状态变量

  • 如果一个状态变量是线程安全的,并且没有任何不变性条件来约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全地发布这个变量

  • 私有构造函数捕获模式:因为构造函数不能使用同步synchronized,要拷贝一个多状态的对象,可以先把要拷贝的对象传到公有构造函数,在公有构造函数中调用私有构造函数,中间通过一个同步方法传递多个状态:
    (https://blog.csdn.net/sinat_34933191/article/details/80557939)

    private SafePoint(int[] a) {
		this(a[0], a[1]);
	}
 
	public SafePoint(SafePoint p) {
		this(p.get());
	}
 
	public synchronized int[] get() {
		return new int[] { x, y };
	}
	
	public SafePoint(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	//线程不安全
	//safePoint2.x, safePoint2.y看到的可能不是同一个snapshot的safePoint2
	public SafePoint2(SafePoint2 safePoint2) {
		this(safePoint2.x, safePoint2.y);
	}

    public synchronized void set(int x, int y) {
		this.x = x;
		// Simulate some resource intensive work that starts EXACTLY at this
		// point, causing a small delay
		try {
			Thread.sleep(10 * 100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.y = y;
	}

在现有的线程安全类中添加功能
  • 最安全的方法是修改原始的类,但通常无法实现;

  • 另一种是扩展这个类,extends,不是所有的类都向子类公开;

  • 第三种是扩展类的功能而不扩展类本身,将扩展代码放入一个“辅助类”中,(但要使用正确的锁进行客户端加锁操作,不要用辅助类的锁去锁了成员变量,没用)

  • 当为现有类添加一个原子操作时,更好的方法是组合,新的类有一个原类的成员,其它方法都照常委托给原类,通过的新类的内置锁保证新添加的和其它原有的方法都是线程安全性;使用时就使用这个新类代替原有的类;(这种方法和第三种的区别在于,第三种中新方法的实现是在客户端,用的还是原类,组合方法包装了一个新类给客户端用)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值