将可变数据限制在单个线程中
当多个线程共享可变数据,每个读或者写的线程都必须执行同步
如下例,去除同步锁则会造成死循环
<代码>私有静态布尔stopRequested; 私有静态同步空白requestStop () { stopRequested=true; } 私有静态同步布尔stopRequested () { 返回stopRequested; } 公共静态void main (String [] args)抛出InterruptedException { 线程backgroundThread=新线程(新Runnable () { @Override 公共空间run () { int i=0; 而(! stopRequested ()) { 我+ +; } } }); backgroundThread.start (); TimeUnit.SECONDS.sleep (1); requestStop (); } 代码><编辑>避免过度同步编辑>
多线程环境下,在观察者模式中使用CopyOnWriteArrayList或CopyOnWriteArraySet(并发场景常用),可以避免死锁,提高并发性。反之在遍历中去修改原有的集合,则可能会导致异常。
在同步区域内,做尽可能少的事情。
大负载服务器:Executors.newFixedThreadPool(),并发过高需要限制线程总数
轻量级程序:Executors.newCachedThreadPool(),自动处理多数情况。
替代计时器:Executors.newScheduledThreadPool(),更为准确,支持多线程,并且能异常恢复。
使用并发集合和同步器,例如ConcurrentMap,无需使用通知和等待。
间歇性计时优先使用系统。nanoTime,它将更精确并免受系统时钟调整影响。
如果维护代码,优先使用notifyAll(),避免不相关线程恶意等待。
文档注释如下安全类型,而非简单用同步判断线程安全,需要注明调用时需要获得哪一把锁
不变的对象绝对是线程安全的,不需要线程同步,如字符串、先导入BigInteger
长,对象自身做了足够的内部同步,也不需要外部同步,如随机的,ConcurrentHashMap,并发集合,原子
对象的部分方法可以无条件安全使用,但是有些方法需要外部同步,需要集合。同步的;有条件线程安全的最常见的例子是遍历由散列表或者向量或者返回的迭代器
对象本身不提供线程安全机制,但是通过外部同步,可以在并发环境使用,如ArrayList HashMap
即使外部进行了同步调用,也不能保证线程安全,这种情况非常少,如如System.setOut (), System.runFinalizersOnExit ()
<编辑>慎用延迟初始化编辑>大多数情况下使用正常初始化。
根据性能差距决定是否延迟初始化(懒加载)。当实例化开销很高并只在部分域访问的时候,可以考虑延迟初始化,同时在多线程下,需要考虑同步。
延迟初始化建议使用双重检查锁(效率比单重大概高25%),并且变量声明波动。
<代码>私人FieldType波动场; 公共FieldType getField () { FieldType结果=字段; 如果(结果==null) { 同步(){ 结果=字段; 如果(结果==null) { ?结果=computeFieldValue (); } } } 返回结果; } 代码>
另一种方式是静态域延迟初始化,原理是静态内部类使用的时候才会进行初始化,并且无需使用同步。
<代码>私有静态类FieldHolder { 静态最终FieldType字段=computeFieldValue (); } 公共静态FieldType getField () { 返回FieldHolder.field; } 代码>
不要依赖线程调度器
依赖线程调度器将使程序缺乏可移植性和健壮性,不依赖线。收益率或者线程优先级。
程序原则是确保可运行线程平均数量不明显多于处理器数量。
避免使用线程组
线程组(ThreadGroup)没有提供它所提及的任何安全功能,不仅如此它提供的功能不完全而且有缺陷,请当它不存在吧。它的替代品是线程池。