《Effective Java》第二版学习笔记之并发编程.
第 66 条 同步访问共享的可变数据
* 关键字 synchronized 可以保证在同一时刻只有一个线程可以执行某个方法或代码块.
* Java 语音规范保证对一个变量的读操作或者写操作是原子性(atomic, 注意 i++ 是非原子性的, 64 位的 long 型或 double 型变量的读写操作也是非原子性的), 但并不保证一个线程写入的值对另一个线程是可见的.
* 避免使用 Thread.stop()方法, 而是采用轮询 (poll) 机制来终止一个线程.
* 如果只需要线程间的交互通信, 而不需要互斥, 可以使用 volatile 关键字.
第 67 条 避免过度同步
* 为了避免活性失败和安全性失败, 在一个被同步的方法或者代码块中, 永远不要放弃对客户端的控制(避免在同步区域调用不可信代码, 否则容易造成死锁, 异常等问题).
* 在同步代码块内做尽可能少的事情.
第 68 条 executor 和 task 优先于线程
* Executor service 可以等待完成一项特殊的任务再继续执行, 也可以优雅的完成终止 (利用 awaitTerminalTermination 方法), 或可以在完成这些任务后逐个的获取这些任务的结果(利用 ExecutorCompletionService) 等.
* 对于轻载的服务器, Executors.newCachedThreadPool 通常是个不错的选择; 对于高负载的服务器, 最好使用 Executors.newFixedThreadPool
* 尽量不要编写自己的工作队列和直接使用线程; 现在关键的抽象不再是 Thread, 而是工作单元(任务, task).
* Timer 只有一个线程来执行任务, 如果唯一的线程抛出了未被捕获的异常, 任务就会终止. ScheduledThreadPoolExecutor 支持多个线程, 并可以优雅的从抛出未受检异常的任务中恢复.
第 69 条 并发工具优先于 wait 和 notify
* 几乎没有任何理由再使用 wait 和 notify 了.
但并不是说不需要掌握, 如维护旧代码可能还是需要了解的, 此种情况下务必确保是利用标准的模式从 while 循环内部调用 wait. 一般情况下优先使用 notifyAll 而不是 notify.
* 使用高级工具:
执行器框架(Executor Framework), 并发集合(Concurrent Collection), 同步器(Synchronizer, 如 CountDownLatch,Semaphore,CyclicBarier 和 Exchanger 等).
第 70 条 线程安全性的文档化
* 线程安全的级别:
(1)不可变的(immutable): 类的实例是不可变的(如 String,Long,BigInteger 等).
(2)无条件的线程安全(unconditionally thread-safe): 类的实例可变, 但有着足够的内部同步(如 Random,ConcurrentHashMap.
(3)有条件的线程安全(conditionally thread-safe): 除了有些方法为了安全的并发使用外部同步之外, 与无条件的线程安全级别相同(如 Collections.synchronized 包装返回的集合, 它们的迭代器要求外部同步).
(4)非线程安全(not thread-safe): 需外部同步(如 ArrayList,HashMap 等).
(5)线程对立(thread hostile): 这个类不能安全的被多个线程并发的使用, 即使所有的方法都被外部同步包围. 线程对立的根源通常在于, 没有同步的修改静态数据.
* 为了避免拒绝服务攻击, 应当使用一个私有锁对象 (private lock object) 来代替同步方法. 私有锁对象只能用在无条件的线程安全类上, 特别适合于专门为继承而设计的类.
第 71 条 慎用延迟初始化
* 正常的初始化优先于延迟初始化.
* 如果出于性能的考虑而需要对静态域使用延迟初始化, 就使用 lazy initiation holder class 模式:
- private static class FieldHolder {
- static final FieldType field = computeFieldValue();
- }
- static FieldType getType() {
- return FieldHolder.field;
- }
* 如果出于性能的考虑而需要对实例域使用延迟初始化, 就使用双重校验锁:
- // volatile 很重要, 保证可见性
- private volatile FieldType field;
- FieldType getField() {
- FieldType result = field;
- if (result == null) {
- synchronized(this) {
- result = field;
- if (result = null) {
- field = result = computeFieldValue();
- }
- }
- }
- return result;
- }
第 72 条 不要依赖于线程调度器
* 不要让应用程序依赖线程调度器, 也不要依赖 Thread.yield 或者线程优先级. 这些设施仅仅对调度器作些暗示.
第 73 条 避免使用线程组
* 最好把线程组当作一个不成功的实验, 就当它们根本不存在一样.
* 考虑使用线程池.
本文地址: https://www.cnblogs.com/laishenghao/p/9740851.html
来源: https://www.cnblogs.com/laishenghao/p/9740851.html