5.3阻塞队列和生产者-消费者模式
BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法。如果队列已经满了,那么put方法将阻塞直到空间可用;如果队列为空,那么take方法将阻塞直到有元素可用。队列可以是有界的也可以是无界的。
如果生产者生成工作的速率比消费者处理工作的速率款,那么工作项会在队列中累计起来,最终好紧内存。同样,put方法的阻塞特性也极大地简化了生产者的编码。如果使用有界队列,当队列充满时,生产者将阻塞并不能继续生产工作,而消费者就有时间来赶上工作的进度。阻塞队列同样提供了一个offer方法,如果数据项不能被添加到队列中,那么将返回一个失败的状态。这样你就能创建更多灵活的策略来处理负荷过载的情况。
在构建高可靠的应用程序时,有界队列是一种强大的资源管理工具:他们能一直并防止产生过多的工作项,使应用程序在负荷过载的情况下边的更加健壮。
5.5信号量
Semaphore中管理着一组虚拟的许可(permit)。许可的初始数量可通过构造函数来指定。在执行操作时可以首先获得许可(只要还有剩余的许可),并在使用以后释放许可。如果没有许可,那么acquire将阻塞直到有许可(或者被中断或者操作超时)。release方法将返回一个许可给信号量。计算信号量的一种简化形式是二值信号量,即初始值为1的Semaphore。二值信号量可以用作互斥体(mutex),并具备不可重入的加锁语义:谁拥有这个唯一的许可,谁就拥有了互斥锁。
5.6构建高效且可伸缩的结果缓存
小结:
- 可变状态是直观重要的(It's the mutable state,stupid)。所有的并发问题都可以归结为如何协调对并发状态的访问。可变状态越少,就越容易确保线程的安全性。
- 尽量将域声明为final类型,除非需要他们是可变的。
- 不可变对象一定是线程安全的。不可变对象能极大地降低并发编程的复杂性。他们更为简单而且可以任意共享而无须使用加锁或保护性复制等机制。
- 封装有助于管理复杂性。在编写线程安全的程序时,虽然可以将所有数据都保存在全局变量中,但为什么要这样做?将数据封装在对象中,更易于维持不变性条件:将同步机制封装在对象中,更易于遵循同步策略。
- 用锁来保护每个可变变量。
- 当保护同一个不变性条件中的所有变量时,要使用同一个锁。
- 在执行复合操作期间,要持有锁。
- 如果从多个线程中访问同一个可变变量时没有同步机制,那么程序会出现问题。
- 不要故作聪明地腿短出不需要使用同步。
- 在设计过程中考虑线程安全,或者在文档中明确地指出他不是线程安全的。
- 将同步策略文档化。
本文转自Ryan.Miao博客园博客,原文链接:http://www.cnblogs.com/woshimrf/p/5251959.html,如需转载请自行联系原作者