第 66 条:同步访问共享的可变数据
1、Java 语言规范保证读写一个变量是原子的,除非类型是 long 和 double。
2、多线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步。
第 67 条:避免过度同步
1、过度同步可能会导致性能降低、死锁,甚至数据破坏。
2、不要在同步区域内部调用外来的方法,尽量限制同步区块内部的工作量。
第 68 条:executor 和 task 优先于线程
1、Java 1.5 增加 java.util.concurrent ,这个包含了 Executor Framework、并发集合(Concurrent Collection)、同步器(Synchronizer)。
final ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable runnable1 = new Runnable() {
public void run() {
for (int i = 1; i < 20; i++) {
if (i < 15) {
System.out.println(i);
} else {
executor.shutdown();// 终止线程
}
}
}
};
executor.execute(runnable1);// 执行线程
2、 Executor Framework 也可以替代 java.util.Timer,即 ScheduledThreadPoolExecutor 更灵活,Timer 更容易。
第 69 条:并发工具优先于 wait 和 notify
第 70 条:线程安全性的文档化
1、不可变的,这个类的实例是不变的。如:String、Long、BigInteger。
2、无条件的线程安全,这个类的实例是可变的,但是这个类有足够的内部同步。如:Random、ConcurrentHashMap。
3、有条件的线程安全,除了有些方法为进行安全的并发使用而需要外部同步之外,这种线程的安全级别与无条件的线程安全相同。如:Collections.synchronized 包装返回的集合。
4、非线程安全,这个类的实例是可变的。如:ArrayList、HashMap。
5、线程对立的,这个类不能安全地被多个线程并发使用。
第 71 条:慎用延迟初始化
1、对于实例域,使用双重检查模式/单重检查模式,延迟初始化。
2、对于静态域。使用 lazy initialization holder class 模式(如:静态内部类初始化静态外部对象)。
3、大多数的域应该正常地进行初始化,而不是延迟初始化,为了达到性能目的或者破坏有害的初始化循环。
第 72 条:不要依赖于线程调度器
1、使用 Thread.sleep(1) 替代 Thread.yield 来进行并发测试。
2、不要让应用程序的正确性依赖于线程调度器。
第 73 条:避免使用线程组
1、线程系统:线程、锁、监视器、线程组。
2、使用线程池 executor 替代线程组。