对象的共享一记

发布对象

发布与逸出

发布(Publish)”一个对象的意思是指,使对象能够在当前作用域之外的代码中使用。

与之相反的情况,逸出(Escape)就是指某个不该发布的对象被发布时,这种情况就是了。

public static Set<Secret> secretList;

public void init() {
	secretList = new HashSet<Secret>();
}

上述代码,当发布对象secretList时,可能会间接地发布其他对象。如果将一个Secret对象添加到集合secretList中,那么会同样发布这个对象,因为任何代码都可以遍历这个集合,并获得集合中的Secret对象的引用。对于集合中的对象来说,就是一种“逸出”。

上述代码中显示的是比较明显的逸出,还有一种隐式的逸出,代码如下:

public class ThisEscape {
	public ThisEscape(EventSource source) {
		source.registerListener (
			new EventListener() {
				public void onEvent(Event e) {
					doSomeThing(e);
				}
			});
	}
}

当ThisEscape发布EventListener时,也隐含地发布了ThisEscape实例本身,因为在这个内部类的实例中包含了对ThisEscape实例的隐含引用。

所以,不要在构造过程是使this引用逸出。

线程封闭

当访问共享的可变数据时,通常需要使用同步。一种避免使用同步的方式就是不共享数据。如果仅在单线程内访问数据,就不需要同步。这种技术被称为线程封闭(Thread Confinement),它是实现线程安全性的最简单方式之一。

Ad-hoc线程封闭

指维护线程封闭性的职责完全由程序实现来承担。这种方式比较弱,因为没有一种语言特性,例如可见性修饰符或局部变量,能将对象封闭到目标线程上。

在volatile变量上存在一种特殊的线程封闭。只要能确保只有单个线程对共享的volatile变量执行希尔操作,那么就可以安全地在这些共享的volatile变量上执行“读取——修改——写入”的操作。这相对于将修改操作封闭在单个线程中以防止发生竞态条件,并且volatile变量的可见性确保了其他线程能看到最新的值。

栈封闭

在栈封闭中,只能通过局部变量才能访问对象。

比如函数中的局部变量。

ThreadLocal类

与线程绑定的类,所以多线程下是安全的。

不变性

满足同步需求的另一种方法是使用不可变对象(Immutable Object)。

不可变对象一定是线程安全的。

不可变对象很简单。它们只有一种状态,并且该状态由构造函数来控制。

对象不可变需要同时满足下面3个条件

  • 对象创建以后其状态就不能改变。
  • 对象的所有域都是final类型。
  • 对象是正确创建的(在对象的创建期间,this引用没有逸出)。

final域

关键字final用于构造不可变性对象。

其能确保初始化过程的安全性,从而可以不受限制地访问不可变对象,并在共享这些对象时无需同步。

安全发布

几种特殊情形

1.单线程下

单线程下,怎么发布都是安全发布。

2.不可变对象

任何线程都可以在不需要额外同步的情况下安全地访问不可变对象,即使在发布这些对象时没有使用同步。这里面要注意不可变对象的三个条件。

3.事实不可变对象

对方发布后,不会被修改,这种情况下,任何线程对这样的对象的访问都是安全的。

安全发布的常用模式

可变对象必须通过安全的方式来发布,这通常意味着在发布和使用该对象的线程时都必须使用同步。

要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造对象可以通过一下方式来安全地发布:

  • 在静态初始化函数中初始化一个对象引用。
  • 将对象的引用保存到volatile类型的域或者AtomicReferance对象中。
  • 将对象的引用保存到某个正确构造对象的final类型域中。
  • 将对象的引用保存到一个由锁保护的域中。

安全的共享可变对象

可变对象在安全发布下可以确保“发布当时”状态的可见性。对于后续操作(比如修改)的可见性,需要通过同步来确保操作的可见性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值