Java多线程常见陷阱

32
Java 并并并并并并并并并 [email protected]( 并并 )

description

杭州交流的PPT

Transcript of Java多线程常见陷阱

Page 1: Java多线程常见陷阱

Java并发编程的常见陷阱

[email protected](伯岩 )

Page 2: Java多线程常见陷阱

不要把并发当成万能锤子

多线程 != 性能提升

Page 3: Java多线程常见陷阱

Amdahl定律

。如果 F是必须串行化执行的比重,那么 Amdahl定律告诉我们,在一个 N处理器的机器中,我们最多可以加速:

Page 4: Java多线程常见陷阱

正确使用读写锁

读时不能写写时不能读可以并发读不能并发写读写比例高

Page 5: Java多线程常见陷阱

——典型错误 LRUMap简单实现

继承 LinkedHashMap, enableLRU设置为 true,覆写 removeEldestEntry方法,使用读写锁同步

读时不能写 √写时不能读 √ 可以并发读 Ⅹ不能并发写 √读写比例高 √

Page 6: Java多线程常见陷阱

在构造函数中启动线程

继承带来的隐患

Page 7: Java多线程常见陷阱

问题

假设 A的构造函数中启动某个线程,该线程读取 A中的实例变量 iB继承 A,并在构造函数中重新给 i赋值 问题: B的实例初始化,首先初始化父类 A,启动线程,线程此时读取的 i非 B所期望。解决: 1 ——、不允许继承 final 2、单独的 start方法(推荐)

Page 8: Java多线程常见陷阱

正确使用 wait/notify

一个世界在等待

Page 9: Java多线程常见陷阱

常见问题

代码 :

问题: 未同步 If替代 while——虚假唤醒 notify替代 notifyAll——被遗忘的线程

Page 10: Java多线程常见陷阱

Atomic+Atomic!=Atomic

MethodA is thread-safeMethodB is thread-safe组合起来还是线程安全的吗?public void methodC(){ MethodA(); MethodB();}

Page 11: Java多线程常见陷阱

我要同步

容器是同步的,就没有问题了吗?

同步的不是容器,而是寂寞

Page 12: Java多线程常见陷阱

正确处理中断

将中断进行到底

Page 13: Java多线程常见陷阱

Thread.interrupt()干什么了 ?

设置中断状态中断阻塞操作

Page 14: Java多线程常见陷阱

How

wait,sleep,join都是 native mthod,直接抛出 InterruptedException

InterruptibleChannel,关闭连接,抛出 ClosedByInterruptException(AbstractInterruptibleChannel.java):

Page 15: Java多线程常见陷阱

错误案例 1

取消任务 ,取消不了 ?

Page 16: Java多线程常见陷阱

错误案例 2

吞掉中断,上层代码怎么办?

Page 17: Java多线程常见陷阱

错误案例 3

包装成 Runtime异常?

Page 18: Java多线程常见陷阱

取消任务的正确做法

没有阻塞操作, volatile状态变量不响应中断的阻塞操作,如 socket.read()之类,关闭 socket。响应中断的阻塞操作(如 sleep,wait,join等),推荐状态变量 +捕捉中断异常

Page 19: Java多线程常见陷阱

处理 InterruptedException

除非你明确知道你在干什么,否则不要简单地 catch并忽略声明 Check异常,继续抛出,交给他人处理重设中断状态,让上层代码发现中断状态。

Page 20: Java多线程常见陷阱

嫁错郎,加错锁

女怕嫁错郎

Page 21: Java多线程常见陷阱

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

Page 22: Java多线程常见陷阱

错误案例 1

只把杭州当汴州

问题: foo是 null? 改变了 foo指向的对象,加锁形同虚设

Page 23: Java多线程常见陷阱

错误案例 2

躲猫猫

问题: Bar跟 Foo的 test方法中的锁不一样。

Page 24: Java多线程常见陷阱

错误案例 3

对同步的容器加锁,使用的锁与容器内部使用的锁不一定是同一个。

HashTable、 Vector √ConcurrentHashMap X

Page 25: Java多线程常见陷阱

不一致的同步

int的读写,问题不是太大

Page 26: Java多线程常见陷阱

邂逅Map

忘记我的另一半,不可原谅

Page 27: Java多线程常见陷阱

阿甘,先别 run

美国犀利哥

Page 28: Java多线程常见陷阱

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方法,因此不会有问题。

Page 29: Java多线程常见陷阱

正确使用 Volatile

Volatile能做什么?状态标识,如取消任务线程安全发布,如修复 DLC问题开销较低的读写锁

Page 30: Java多线程常见陷阱

正确使用 Volatile

Volatile不能做什么? 不能用于做计数器 与其他变量构成不变式

Page 31: Java多线程常见陷阱

规避 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到最新稳定版。

Page 32: Java多线程常见陷阱

End,Thanks