Java并发编程实战--死锁
今天看了第十章,描述了经典的“哲学家进餐”问题,Google 哲学家进餐 就有 ,不多解释。先解释一下锁:可以这么理解,每一个java对象都具有一个锁标记,而这个锁标记只能同时分配给一个线程,然后讲了死锁的产生原因:当一个线程永远地持有一个锁,而且其他线程都想要取得这个锁时,那么它们将永远被阻塞。下面用三种介绍三种“死锁”状况。
一.死锁
先看代码
出现死锁的原因是:两个线程以不同顺序来获取相同的锁。如果以相同的顺序来获取锁,就不会出现循环的加锁依赖性,也就不会出现死锁。
二.动态的死锁
看代码
package 并发编程;import java.awt.Image;import java.util.Set;/** * 出租车车队类,指挥出租车的调动 * @author Andre * */public class Dispatcher {private final Set<Taxi> taxis;//出租车集合private final Set<Taxi> availableTaxis;///可用出租车集合public Dispatcher(Set<Taxi> taxis , Set<Taxi> availableTaxis){this.taxis = taxis;this.availableTaxis = availableTaxis;}public synchronized void notifyAvailable(Taxi taxi) {availableTaxis.add(taxi);}/** * 获得包含当前出租车的完整画面 * @return */public synchronized CarImage getImage(){CarImage image = new CarImage();for(Taxi t: taxis)image.drawMarker(t.getLocation());return image;}}这两个类中,并没有显式地获取两个锁,但实际上,现在有一个Dispatcher对象和多个Taxi对象(即一个出租车车队和多辆出租车),A线程调用Taxi对象中的setLocation时,方法内部调用dispatcher.notifyAvailable(),该方法也加上了同步关键字synchronized,这样A线程就先后获取了Taxi对象和Dispatcher对象的锁。而同时B线程调用dispatcher.getImage(该方法有同步标记),而方法内部调用了t.getLocation也是一个同步方法,这样B线程就先后获取了Dispatcher对象和Taxi对象的锁。这样就回到了上面说过的危险情况:两个线程试图用不同顺序获取相同的锁。而这种情况也是更加难以被程序员发现出来的,因为它更加隐蔽。