在安全性和活跃性之间通常存在着某种制衡
一、死锁
定义:在线程A持有锁L并想获得锁M的同时,线程B持有锁M并尝试获得锁L,线程AB均不会释放自己的锁,那么这两个线程将永远地等待下去
在数据库系统的设中考虑了检测死锁以及从死锁中恢复。JVM没有办法解决死锁,只能在编程和测试时注意不要让死锁发生
1、锁顺序死锁——两个线程试图以不同的顺序来获得相同的锁
解决:如果所有线程以固定的顺序来获得锁,那么在程序中就不会出现锁顺序死锁问题。
2、动态的锁顺序死锁
1 A: transferMoney(myAccount, yourAccount, 10); 2 B: transferMoney(yourAccount, myAccount, 20);
使用Account中包含的唯一的不可变的并且具备可比性的键值或计算HashCode作为加锁顺序的依据
3、在协作对象间发生死锁
如果在持有锁时调用某个外部方法,那么将出现活跃性问题。在这个外部方法中可能会获取其他锁(这可能会产生死锁),或者阻塞时间过长,导致其他线程无法及时获得当前被持有的锁。
1 class Taxi { 2 @GuardedBy("this") private Point location, destination; 3 private final Dispatcher dispatcher; 4 5 public Taxi(Dispatcher dispatcher) { 6 this.dispatcher = dispatcher; 7 } 8 9 public synchronized Point getLocation() { 10 return location; 11 } 12 13 public synchronized void setLocation(Point location) { 14 this.location = location; 15 if (location.equals(destination)) 16 dispatcher.notifyAvailable(this); 17 } 18 19 public synchronized Point getDestination() { 20 return destination; 21 } 22 23 public synchronized void setDestination(Point destination) { 24 this.destination = destination; 25 } 26 } 27 28 class Dispatcher { 29 @GuardedBy("this") private final Set<Taxi> taxis; 30 @GuardedBy("this") private final Set<Taxi> availableTaxis; 31 32 public Dispatcher() { 33 taxis = new HashSet<Taxi>(); 34 availableTaxis = new HashSet<Taxi>(); 35 } 36 37 public synchronized void notifyAvailable(Taxi taxi) { 38 availableTaxis.add(taxi); 39 } 40 41 public synchronized Image getImage() { 42 Image image = new Image(); 43 for (Taxi t : taxis) 44 image.drawMarker(t.getLocation()); 45 return image; 46 } 47 }
taxi.setLocation(location) 和dispatcher.notifyAvailable(taxi)同时调用时会发生锁顺序死锁
4、开放调用——在调用某个方法时不需要持有锁
在程序中应尽量使用开放调用。与那些在持有锁时调用外部方法的程序相比,更易于对依赖于开放调用的程序进行死锁分析
1 class Taxi { 2 @GuardedBy("this") private Point location, destination; 3 private final Dispatcher dispatcher; 4 5 public Taxi(Dispatcher dispatcher) { 6 this.dispatcher = dispatcher; 7 } 8 9 public synchronized Point getLocation() { 10 return location; 11 } 12 13 public synchronized void setLocation(Point location) { 14 boolean reachedDestination; 15 synchronized (this) { 16 this.location = location; 17 reachedDestination = location.equals(destination); 18 } 19 if (reachedDestination) 20 dispatcher.notifyAvailable(this); 21 } 22 23 public synchronized Point getDestination() { 24 return destination; 25 } 26 27 public synchronized void setDestination(Point destination) { 28 this.destination = destination; 29 } 30 } 31 32 @ThreadSafe 33 class Dispatcher { 34 @GuardedBy("this") private final Set<Taxi> taxis; 35 @GuardedBy("this") private final Set<Taxi> availableTaxis; 36 37 public Dispatcher() { 38 taxis = new HashSet<Taxi>(); 39 availableTaxis = new HashSet<Taxi>(); 40 } 41 42 public synchronized void notifyAvailable(Taxi taxi) { 43 availableTaxis.add(taxi); 44 } 45 46 public Image getImage() { 47 Set<Taxi> copy; 48 synchronized (this) { 49 copy = new HashSet<Taxi>(taxis); 50 } 51 Image image = new Image(); 52 for (Taxi t : copy) 53 image.drawMarker(t.getLocation()); 54 return image; 55 } 56 }