《Effective Java》 学习笔记 —— 并发

 

  《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 模式:

1 private static class FieldHolder {
2     static final FieldType field = computeFieldValue();
3 }
4 
5 static FieldType getType() {
6     return FieldHolder.field;
7 }

  * 如果出于性能的考虑而需要对实例域使用延迟初始化,就使用双重校验锁:

 1 // volatile 很重要,保证可见性
 2 private volatile FieldType field;
 3 
 4 FieldType getField() {
 5     FieldType result = field;
 6     if (result == null) {
 7         synchronized(this) {
 8             result = field;
 9             if (result = null) {
10                 field = result = computeFieldValue();
11             }
12         }
13     }
14     return result;  
15 }

 

第72条 不要依赖于线程调度器

  * 不要让应用程序依赖线程调度器,也不要依赖 Thread.yield 或者线程优先级。这些设施仅仅对调度器作些暗示。

 

第73条 避免使用线程组

  * 最好把线程组当作一个不成功的实验,就当它们根本不存在一样。

  * 考虑使用线程池。

 

本文地址:https://www.cnblogs.com/laishenghao/p/9740851.html

 

posted @ 2018-10-04 16:19  (•̀ω•́)y  阅读(516)  评论(0编辑  收藏  举报