java并发编程(二)
所有的并发问题,都可以归结为如何协调对并发状态的访问,可变状态越少,就越容易确保线程安全性
尽量将域声明为final类型,除非他们是可变的
不可变对象一定是线程安全的,
不可变对象能极大地降低并发编程的复杂性,他们更为简单和安全,可以任意共享而无需使用加锁,或保护性复制等机制
封装有助于管理复杂性
在编写线程安全的程序时,虽然可以将所有数据保存到全局变量中,但为什么要这样做?将数据封装在对象中,更易于维护不变性条件,将同步机制装在对象中,更易于遵循同步策略
用锁来保护每个可变变量
当保护同一个不变性条件中的所有变量时,要使用同一个锁
在执行复合操作期间,要持有锁
如果从多个线程中访问同一个可变变量时没有同步机制,那么程序可能出现问题,不要故作聪明地判断出不需要使用同步
在设计过程中考虑线程安全,或者在文档中明确地指出它不是线程安全的
将同步策略文档化
结构化并发应用程序
串行地执行任务
只处理一个请求,请求处理结束下一个请求才会被处理,不然就一直等待
不要这么做
显示地为任务创建线程
为每一个请求创建一个线程,不要这么做
Executor框架
线程池简化了线程的管理工作,任务执行的主要抽象不是thread,而是executor,虽然它是一个接口,但它却为灵活且强大的异步任务执行框架提供了基础,它提供了一种标准的方法将任务的提交过程与执行过程解构开来,并用runnable表示任务,executor的实现还提供了对生命周期的支持,以及统计信息收集,应用程序管理机制和性能监视等机制
线程创建和销毁开销巨大,所以有了线程池,线程跑完归还线程池,并不会被销毁
线程的开启关闭和中断
任务取消
中断,及中断策略,响应中断,Future
停止基于线程的服务
毒丸对象
jvm关闭
。。。
线程池的使用
在任务与执行策略之间的耦合
设置线程池的大小
配置threadpoolexecutor
扩展
活跃性,性能。测试
死锁的诊断和避免
其他活跃性危险:饥饿,丢失信号,活锁
活跃性故障是一个非常严重的问题,,因为出现这种情况,除了终止程序,无他办法,最常见的故障就是锁顺序死锁,在设计程序时应避免产生,确保线程在获取多个锁采用一致的顺序,最好的解决办法是在程序中始终处于开放调用,,这将大大减少,需要同时持有多个锁的地方,
性能与可伸缩性
增加计算机资源,程序的处理能力和吞吐量也将提高
显示锁
在jdk5.0之前,在协调对共享对象的访问时可以使用的机制只有。synchronized和volatile,5.0增加了一种新的机制Reentrantlock,与之前提到过的机制相反,它不是替代内置加锁的方法,而是当内置加锁机制不适用时,作为一种可选择的高级功能
与内置加锁机制不同的是,Lock提供了一种无条件的,可轮询的,定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显示的