Effective Java读书笔记(四):并发
来源:互联网 发布:淘宝的延长收货是几天 编辑:程序博客网 时间:2024/04/30 07:15
前言
以前当我在网络上看到爆发语言大战时,也会在一旁“看戏”,这个语言怎样怎样,那个语言怎样怎样,感觉挺有趣的,我对其中的褒贬也会半信半疑。后来我慢慢对这些言论不再感兴趣,基本上看到就会跳过,除非是对多门语言都非常熟悉的人发表的,比如说某知乎大v曾经写的Java sucks,C# rocks
文章,这样的文章才更值得一读。这样的想法转变是因为,一般而言当我对任何东西更加熟悉时,我才会更加知道原来自己不懂的东西还有更多。
今天总结的是《Effective Java》里并发
这个专题。
并发
1. 同步访问共享的可变数据
这一小节就是试图让我们弄清楚Java:线程同步的一些概念,当搞清楚这些概念后,才能明白怎样正确的处理同步。
当多个线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步,如果没有同步,就不能保证一个线程所做的修改,可以被另外一个线程获知。
2. 避免过度同步
这一节内容有点深,暂时还不能消化不下来……
过度同步可能会导致性能降低、死锁、甚至不确定的行为。通常,你应该在同步区域内尽量不要调用外来方法
,并且尽量限制同步区域的工作量,获得锁,处理共享数据,释放锁。
3. executor和task优先线程
这一小节简单介绍了下线程池Java:线程池基础,还有Executor Framework的一些功能,比如Executor Framework能非常简单地完成以下工作:
- 等待一个任务集合中的任何任务或者所有任务完成(
ExecutorService#invokeAny/All
方法) - 优雅地中断或终止任务(
shutdown/shutdownNow/awaitTermination
) - 任务完成时逐个获取这些任务结果(
ExecutorCompletionService
) - …
总而言之,作者提醒我们,要优先使用Executor Framework而非直接使用线程来处理任务和实现并发
,至于怎么使用文章并未讨论太多,这个需要读者专门学习。
4. 并发工具优先于wait和notify
Java1.5发行版本中,添加了一个并发工具包java.util.concurrent
,其中就包括第3点的Executor Framework
,另外还包括并发集合
以及同步器
。
并发集合为标准的集合接口(List、Queue、Map)提供了高性能的并发实现。为了提供高并发性,这些实现在内部自己管理同步。比如ConcurrentHashMap
以及各种BlockingQueue
实现。
同步器是一些使线程能够等待另一个线程的对象
,允许他们协调动作
,没有同步器之前,过去常常使用wait/notify
组合来实现。最常用的同步器是CountDownLatch
和Semaphore
,比较不常用的是CyclicBarrier
和Exchanger
。虽然始终应该优先使用并发工具,但是还是要明白wait方法的标准模式以维护遗留代码:
Synchronized(obj){ while(condition does not hold) obj.wait();}
与第3节一样,作者只是提醒我们应该使用并发工具,至于怎么使用文章并未讨论太多,这个需要读者专门学习,《Java编程思想》里面有一个节专门就是将同步器的,还有一些并发集合的。
5. 线程安全性的文档
总而言之,必要的时候(文中写的是每个类都应该,但是现实中几乎不太可能),必须清楚地在文档中说明它的线程安全属性。集中常见的情形如下:
- 不可变的:类实例不可变,所以不需要同步,比如
String
。 - 无条件的线程安全:类的内部已经做好同步,它的实例可以被并发使用,无需任何外部同步,比如
ConcurrentHashMap
。 - 有条件的线程安全:有些方法需要外部同步,比如Conllections.synchronized包装返回的集合,它的的迭代器(iterator)要求外部同步。
- 非线程安全:并发时调用这些实例的方法时必须实施同步,比如
ArrayList和HashMap
。 - 线程对立的:不能并发使用,JDK中这样的类非常少~
上述几种情况也可以概括为:不可变、线程安全、线程不安全
三种情况。
6. 慎用延迟初始化
如果域只有在类的实例部分被访问,并且初始化的开销很高,才值得进行延迟初始化。否则大多数的域都应该正常地初始化,而不是延迟初始化。假设真的有必要进行,也还应该注意线程同步的问题:
- 对于实例域,使用双重检查模式
private volatile Instance ins;public Instance getInstance(){ if(ins == null){ synchronized(this){ if(ins == null) ins = new Instance(); } } return ins;}
- 对于静态域,使用内部类(实例域也可以用这个方法实现单例)。
private static Instance ins;private static class InstanceHolder{ static final Instance INS = new Instance();}public static Instance getInstance(){ return InstanceHolder.INS;}
- 可以接受重复初始化的
private Instance ins;public Instance getInstance(){ if(ins == null) ins = new Instance(); return ins;}
7. 不要依赖于线程调度器
不要让程序的正确性依赖于线程调度器,比如常见的是调用Thread.yield方法以及设置线程优先级,这些措施仅仅对调度器做些暗示,没有任何机制保证它将会被采纳。
8. 避免使用线程组
简而言之线程组有多bug,你可以忽略掉它们,就当根本不存在一样。
- Effective Java读书笔记(四):并发
- Effective Java读书笔记四
- effective java读书笔记四
- Effective java 读书笔记( 四 )
- Effective Java读书笔记一:并发
- Effective Java读书笔记(四)
- effective java 读书笔记(四)
- 【读书笔记】《Effective Java》(9)--并发
- effective java 读书笔记---第10章 并发
- Effective Java 读书笔记(九):并发
- Java并发读书笔记(四)
- Effective Java读书笔记四:通用程序设计
- Effective Java 读书笔记(四):泛型
- <<Effective C++>读书笔记(四)
- Effective C++读书笔记四
- effective c++读书笔记(四)
- 《JAVA并发编程实践》读书笔记(四)
- 《Effective java》读书笔记9——线程并发
- 文章标题
- zju1610 Count the Colors
- 【bzoj2724】[Violet 6]蒲公英
- 文章标题
- leetcode.85. Maximal Rectangle
- Effective Java读书笔记(四):并发
- Windows系统设置开机启动项的方法
- 文章标题
- QT中实现定时器
- JAVA反射(一)获取Class对象的三种方式及其区别
- 文章标题
- OBIEE提示器中出现为空的一条记录
- 运输问题[网络流24题之17]
- NOJ——1274The battle of Red Cliff(并查集按秩合并)