【读书笔记】《Effective Java》(9)--并发
来源:互联网 发布:海口数据共享交换平台 编辑:程序博客网 时间:2024/05/01 01:56
这一部分应该是Java很难的一部分,不过《Effective Java》讲到的不算多,建议先补一下Java多线程的知识,比如,我这几天找到Java并发编程这里,恶补了下多线程的知识。
并发
66. 同步访问共享的可变数据
同步不仅是互斥地访问对象,还意味着其他线程对于对象的操作(线程间可靠的通信),己方可见
Java语言规范保证读或者写一个变量是原子的,除非这个变量的类型为long或double(这是书上的原话,不过我查了一下,改为给一个基本变量读取或者赋值是原子的更好,至于long和double,我想是因为它们存储空间占两个寻址空间,读取时需要两次寻址,高32位低32位这样,所以不能保证原子性)
活性失败:指因为JVM的优化,导致一段代码不能及时有效地被执行而并发失败的现象,这并不会产生任何异常,但会因为临界条件无法达到,一部分代码一直不能得到执行
- 安全失败:指因为代码没有良好的同步,导致预期目标没有实现而并发失败的现象,这并不会产生任何异常,但是得到的结果并不是我们想要的
67. 避免过度同步
本条建议:
- 开放调用:即将外来代码的调用放到同步区域之外,同步区域只执行尽可能少的工作
- 如果一个类不是为了并发而设计的,那么不要使用内部同步(内部类的设计的时候使用同步的方法),而是让客户自己在必要时刻进行外部同步。
Java平台没有遵守建议的类:StringBuffer,它是内部同步的,但常常用于单线程
68. executor和task优先于线程
现在应当优先使用executor和task而不是Thread或者Runnable,因为在以前Thread既是工作单元又是执行单元,但是现在二者分离,executor是执行单元,Runnable和Callable是工作单元
使用ScheduledThreadPool代替Timer作为多线程的定时器
对于ThreadPool:
- 使用Executor.newCachedThreadPool来应对一个轻负载的服务器
- 使用Executor.newFixedThreadPool来应对一个重负载的服务器
- 为了最大限度控制,直接使用ThreadPoolExecutor
69. 并发工具优先于wait和notify
Java并发包包含Executor Framework、并发集合以及同步器三大部分
使用同步器而不是wait和notify
使用wait和notify的建议:
- 使用wait的正确方式:在循环中调用wait
synchronized(obj){ while(<condition does not hold>){ obj.wait(); }}
- 使用notifyAll而不是notify避免恶意访问
70. 线程安全性的文档化
线程安全的级别:
- 不可变:类的实例是不可变的,也就是无需同步,也不会出并发问题
- 无条件的线程安全:类的实例是可变的,但是实现了足够的内部同步,可以并发,例如并发包内的集合类
- 有条件的线程安全:除了有些方法为了进行安全的并发而使用外部同步之外,线程安全级别和无条件的线程同步相同,例如Collections.synchronized返回的类,其iterator(迭代器)需要外部同步
- 非线程安全:实例可变,为了并发使用,需要客户代码对其进行外部同步每个方法,例如一般的集合类
- 线程对立:不能安全地被多个线程并发,根源通常在于,没有同步地修改静态数据
本条建议:
- 如果编写无条件的线程安全类,建议使用私有锁,隐藏内部实现,私有锁尤其适合于专门为继承而设计的类
- 如果编写有条件的线程安全类,一定要在API文档中注明哪个方法调用序列需要外部同步,以及执行这些序列需要哪把锁
71. 慎用延迟初始化
四种延迟初始化方式:
- 最普通的:
private FieldType field;synchronized Field getField(){ if(field==null){ field=computeFieldValue(); } return field;}
- 对静态域的出于性能考虑的初始化方式(lazy initialization holder class):
private static class FieldHolder{ static final FieldType field=computeFieldValue();}static FieldType getField(){return FieldHolder.field;}
- 双重检查模式(出于性能考虑,避免初始化之后的锁定访问的开销):
private volatile FieldType field;Field getField(){ FieldType result=field; if(result==null){ synchronized(this){ result=field; if(result==null){ field=result=computeFieldValue(); } } } return result;}
- 单重检查模式(双重检查模式的变式,可以接受重复初始化):
“`java
private volatile FieldType field;
private FieldType getField(){
FieldType result=field;
if(result==null){
field=result=computeFieldValue();
}
return result;
}
“`
72. 不要依赖于线程调度器
- 本条建议:
- 线程只做有意义的工作,不应该忙等
- 不要依赖Thread.yield改变优先级,因为它在不同环境下效果不同,而且实现也不同
- 不要使用调整线程优先级的方法,它不具有可移植性
- 线程优先级可以提高本来就可以正常工作的程序的服务质量,而不能修正一个本来不能工作的程序
73. 避免使用线程组
- 线程组已经是一个废弃的类,在Java1.5之后不应当使用
- 【读书笔记】《Effective Java》(9)--并发
- Effective Java 读书笔记(九):并发
- Effective Java读书笔记(四):并发
- Effective Java读书笔记一:并发
- 《Effective java》读书笔记9——线程并发
- Effective Java读书笔记(第10章-并发)
- Effective Java读书笔记一:并发(66-73)
- effective java 读书笔记---第10章 并发
- Effective.Java 读书笔记(9)关于HashCode
- Effective Java 读书笔记(一)
- Effective Java 读书笔记(二)
- Effective Java读书笔记(一)
- Effective Java读书笔记(一)
- Effective Java读书笔记(二)
- Effective Java读书笔记(三)
- Effective Java读书笔记(四)
- effective java读书笔记 (二)
- Effective Java读书笔记(五)
- Android wifi连续通断测试
- UVA 3708 Graveyard(思维)
- 第五周项目4-数制转换
- 利用动态代理模式来增强方法
- Chrome自带的开发者工具进阶技巧
- 【读书笔记】《Effective Java》(9)--并发
- CDOJ 1324 (分块样例)
- android性能优化----页面跳转优化
- angularJS学习笔记之——搭建学习环境
- 第五周星期四
- ClippingNode 用法
- JSP内置对象
- Google Protocol Buffer 的使用和原理
- 策略模式(Strategy)