Java并发编程实战~笔记~章三

3.1 可见性

这部分我没怎么看懂。或许是我受限于技术视野,无法找到书中描述的多线程运行的环境。

几个点:

1、重排序。

按书中的说法,重排序并不是一个稀奇的特性,屏蔽重排序细节的方法是——只要是共享的数据,就进行正确的同步。(实际上我从未见过重排序的情况,哪怕根据书中用例进行试验)。

2、失效数据。

这似乎也不是什么很值得提出的点。因为有时共享数据并不需要严格的准确性,比如 while (isRunning) {}这种控制变量,如果没有其他不变性条件约束,那么这个变量生效稍稍晚一次循环,又有什么问题呢?它的循环中的耗时肯定是远大于这次判断的,即使使用同步代码,isRunning也没有办法立刻生效啊,它总是要等待内部循环一次结束以后,才能进行判断。

假如isRunning参与了其他共享变量的不变性条件,那么必然是会对这些共享变量进行统一的加锁。也没有单独提出来的意义。

3.2 发布与逸出

这个还是很实用的概念。“发布”一个对象的意思是指,使对象能够在当前作用域之外的代码中使用。比如在类里面,声明一个public属性;在public方法中,直接或者间接返回某个私有属性;或者返回某个内部类对象。

这里很重要的一个点就是:不要在构造器中,发布this(这是逸出的一种情况)。

错误的使用方式示例:

public class ThisEscape {
	public ThisEscape(EventSource source) {
		source.registerListener(new EventListener(){
			public void onEvent(Event e) {
				doSomething(e);
			}
		});
	}
}
这个进行构造的线程一旦将EventListener发布出去,那么间接的this也被发布出去了。假如另一个线程立刻就进行事件回调,那么就会出现这种情况:对象还没有构造完成,就被使用了,这种情况非常危险,因为它从一开始就破坏了对象的一致性状态。
还有一些类似的构造器中this逸出的情况:

public class ThisEscape implements Runnable{
	public ThisEscape() {
		new Thread(this).start();
	}
	public void run() {
		doSomething();
	}
}
安全的对象构造过程,可以尝试使用工厂方法封装构造方法,来防止this逸出。
3.3 线程封闭

线程封闭技术:将共享的可变数据,变成仅在单线程内访问,就不需要同步了。

这个概念看起来很不可思议,既然是要共享的数据,又怎么能变成仅在单线程内访问呢?

其实道理很简单,就是对象拷贝。比如一个功能模块有一个输入队列,你可以有两种方式实现同步。一种是针对队列的每种操作,设计同步方法,这是比较复杂的,如果有增删改查这些操作,往往同步方法的体积和数量越来越大。另一种方法,就是先从输入队列取一批数据,拷贝到另一个地方,然后对拷贝的队列进行操作,这样的话,对于拷贝队列而言,就只有功能模块一个线程在用,再怎么玩都不需要同步,这种实现方式需要同步的方法,就只有插入数据,和批量拷走数据两个了。

这个思路我自己觉得是非常简单实用的!

至于书里说的ThreadLocal的例子,并不能算是一个通用的方式。ThreadLocal只是一个中转的类,把拷贝数据分发到各个线程对象里面去了,和直接用set方法塞进线程没有什么区别。

但是里面另一个小例子却很有意思,给出了另一种缩短同步代码执行时间的思路。

它的做法是,将所有共享变量,一起封装成一个类型,变成一个共享变量。这种处理下,多个变量进行不变性约束的计算,就不需要放在同步代码里面了,只要算好以后,在同步代码中,将封装好的共享变量一次性放进去就行了。

上面两种方法,用一句话概括大概可以这样说:1、共享数据拷贝到线程内,进行单线程处理,消除多余同步。2、不变性约束封装在一个变量里,对变量进行同步,消除不变性约束计算占用的同步时间。


其他内容我就看不懂了,也觉得没什么实用性。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值