Java多线程常见陷阱
-
Upload
dennis-zhuang -
Category
Technology
-
view
6.401 -
download
7
description
Transcript of Java多线程常见陷阱
Java并发编程的常见陷阱
[email protected](伯岩 )
不要把并发当成万能锤子
多线程 != 性能提升
Amdahl定律
。如果 F是必须串行化执行的比重,那么 Amdahl定律告诉我们,在一个 N处理器的机器中,我们最多可以加速:
正确使用读写锁
读时不能写写时不能读可以并发读不能并发写读写比例高
——典型错误 LRUMap简单实现
继承 LinkedHashMap, enableLRU设置为 true,覆写 removeEldestEntry方法,使用读写锁同步
读时不能写 √写时不能读 √ 可以并发读 Ⅹ不能并发写 √读写比例高 √
在构造函数中启动线程
继承带来的隐患
问题
假设 A的构造函数中启动某个线程,该线程读取 A中的实例变量 iB继承 A,并在构造函数中重新给 i赋值 问题: B的实例初始化,首先初始化父类 A,启动线程,线程此时读取的 i非 B所期望。解决: 1 ——、不允许继承 final 2、单独的 start方法(推荐)
正确使用 wait/notify
一个世界在等待
常见问题
代码 :
问题: 未同步 If替代 while——虚假唤醒 notify替代 notifyAll——被遗忘的线程
Atomic+Atomic!=Atomic
MethodA is thread-safeMethodB is thread-safe组合起来还是线程安全的吗?public void methodC(){ MethodA(); MethodB();}
我要同步
容器是同步的,就没有问题了吗?
同步的不是容器,而是寂寞
正确处理中断
将中断进行到底
Thread.interrupt()干什么了 ?
设置中断状态中断阻塞操作
How
wait,sleep,join都是 native mthod,直接抛出 InterruptedException
InterruptibleChannel,关闭连接,抛出 ClosedByInterruptException(AbstractInterruptibleChannel.java):
错误案例 1
取消任务 ,取消不了 ?
错误案例 2
吞掉中断,上层代码怎么办?
错误案例 3
包装成 Runtime异常?
取消任务的正确做法
没有阻塞操作, volatile状态变量不响应中断的阻塞操作,如 socket.read()之类,关闭 socket。响应中断的阻塞操作(如 sleep,wait,join等),推荐状态变量 +捕捉中断异常
处理 InterruptedException
除非你明确知道你在干什么,否则不要简单地 catch并忽略声明 Check异常,继续抛出,交给他人处理重设中断状态,让上层代码发现中断状态。
嫁错郎,加错锁
女怕嫁错郎
Don't
#1: Don’t synchronize on an object you’re changing#2: Don’t synchronize on a String literal#3: Don’t synchronize on auto-boxed values#4: Don’t synchronize on null#5: Don’t synchronize on a Lock object#6: Don’t synchronize on getClass()#7: Be careful locking on a thread-safe object with encapsulated locking
错误案例 1
只把杭州当汴州
问题: foo是 null? 改变了 foo指向的对象,加锁形同虚设
错误案例 2
躲猫猫
问题: Bar跟 Foo的 test方法中的锁不一样。
错误案例 3
对同步的容器加锁,使用的锁与容器内部使用的锁不一定是同一个。
HashTable、 Vector √ConcurrentHashMap X
不一致的同步
int的读写,问题不是太大
邂逅Map
忘记我的另一半,不可原谅
阿甘,先别 run
美国犀利哥
Start Vs. Run
哥只是爱跑步
问题:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4533087在 jdk1.4.2以前,每个 thread初始化都会加入 ThreadGroup,如果你只是调用 run而不是start,那么此 thread将无法被正常回收造成内存泄漏。在 JDK5之后,将加入 ThreadGroup这一步从构造函数转移到 start方法,因此不会有问题。
正确使用 Volatile
Volatile能做什么?状态标识,如取消任务线程安全发布,如修复 DLC问题开销较低的读写锁
正确使用 Volatile
Volatile不能做什么? 不能用于做计数器 与其他变量构成不变式
规避 j.u.c的 bug
LinkedBlockingQueue.poll(time,timeUnit) 内存泄漏,其他 queue也有类似问题http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6460501
Semaphore.tryAcquire 内存泄漏甚至 hang住http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6460501http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6241823
ReentrantReadWriteLock可能在没有任何线程持有锁的情况下被 hang住,这是一系列的 BUG:http://bugs.sun.com/view_bug.do?bug_id=6822370http://bugs.sun.com/view_bug.do?bug_id=6903249
可以说 j.u.c在 1.5这个版本上有非常多的 bug,具体可以查看下 sun的 bug database,推荐升级 jdk到最新稳定版。
End,Thanks