Java并发编程实战
1,不变性
当满足以下条件时,对象才是不可变的:
- 对象创建以后其状态就不可修改
- 对象的所有域都是 final 类型
- 对象是正确创建的(在对象的构造期间,this 引用没有逸出)
从技术上来看,不可变对象并不需要将其所有的域都声明为 final 类型,例如 String 就是这种情况,这就要对类的良性数据竞争情况做精确的分析,因此需要深入理解 Java 的内存模型。
…… 自己在编码时不要这么做。
2,中断策略
对于非线程所有者的代码来说,应该小心地保存中断状态,这样拥有线程的代码才能对中断做出响应。
批评者嘲笑 java 的中断功能,因为它没有提供抢占式的中断机制,而且还强迫开发人员必须处理 InterruptedException。然而,通过推迟中断请求的处理,开发人员能定制更灵活的中断策略,从而使程序在响应性和健壮性之间实现合理的平衡。
3,设置线程池大小
对于计算密集的任务,在拥有 N 个处理器的系统上,当线程池大小为 N+1 时,通常能实现最优的利用率。(即使当计算密集型的线程偶尔由于页缺失故障或者其它原因而暂停时,这个“额外”的线程也能确保 CPU 的时钟周期不会被浪费。)对于包含 I/O 操作或者其它阻塞操作的任务,由于线程并不会一直执行,因此线程池的规模应该更大。 计算每个任务对该资源的需求量,然后用该资源的可用总量除以每个任务的需求量,所得结果就是线程池大小的上限。
4,volatile变量
加锁机制既可以确保可见性又可以确保原子性,而 volatile 变量只能确保可见性。 当且仅当满足以下所有条件时,才应该使用 volatile 变量: - 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。 - 该变量不会与其它状态变量一起纳入到不变性条件中。 - 在访问变量时不需要加锁。