《Java並發編程實戰》第十章 避免活躍性危急 讀書筆記
阿新 • • 發佈:2017-05-06
for 分析 tac mage cas 系統 ron htm 發生
1. 順序死鎖 最少有兩個鎖。一個線程獲取到A鎖須要獲取B鎖才幹進行操作,而另外一個線程獲取到了B鎖。須要獲取A鎖才幹運行操作。這樣的情況下easy出現順序死鎖。
2. 動態的鎖順序死鎖
A: transferMoney(myAccount, yourAccount, 10);
B: transferMoney(yourAccount, myAccount, 20);
由外部傳入的變量全部鎖的條件,可是由以上傳入的變量能夠看到,這樣的情況下會出現一個線程先獲取myAccount鎖在申請yourAccount鎖,而另外一個線程相反先獲取yourAccount鎖在申請myAccount鎖。
3. 在協作對象之間發生的死鎖
4. 開放調用 -- 待填充
5. 資源死鎖 外部鎖常被忽視而導致死鎖,比如數據庫的鎖
2. 通過線程轉儲信息來分析死鎖 通過Dump線程的StackTrace,比如linux下運行命令 kill -3 <pid>,或者jstack –l <pid>,或者使用Jconsole連接上去查看線程的StackTrace,由此來診斷死鎖問題。
一、死鎖
所謂死鎖: 是指兩個或兩個以上的進程在運行過程中。因爭奪資源而造成的一種互相等待的現象。若無外力作用。它們都將無法推進下去。
百科百科
1. 順序死鎖 最少有兩個鎖。一個線程獲取到A鎖須要獲取B鎖才幹進行操作,而另外一個線程獲取到了B鎖。須要獲取A鎖才幹運行操作。這樣的情況下easy出現順序死鎖。
public class LeftRightDeadlock { private final Object left = new Object(); private final Object right = new Object(); public void leftRight() { synchronized (left) { synchronized (right) { // doSomething(); } } } public void rightLeft() { synchronized (right) { synchronized (left) { // doSomething(); } } } }
2. 動態的鎖順序死鎖
public void transferMoney(Account fromAccount, Account toAccount, DollarAmount anount) throws InsufficientResourcesException { synchronized (fromAccount) { synchronized (toAccount) { if (fromAccount.getBalance().compareTo(amount) < 0) { throw new InsufficientResourcesException(); } else { fromAccount.debit(anount); toAccount.credit(anount); } } } }
A: transferMoney(myAccount, yourAccount, 10);
B: transferMoney(yourAccount, myAccount, 20);
由外部傳入的變量全部鎖的條件,可是由以上傳入的變量能夠看到,這樣的情況下會出現一個線程先獲取myAccount鎖在申請yourAccount鎖,而另外一個線程相反先獲取yourAccount鎖在申請myAccount鎖。
private static final Object tieLock = new Object(); public void transferMoney(final Account fromAccount, final Account toAccount, final DollarAmount anount) throws InsufficientResourcesException { class Helper{ public void transfer() throws InsufficientResourcesException { if (fromAccount.getBalance().compareTo(amount) < 0){ throw new InsufficientResourcesException(); } else{ fromAccount.debit(anount); toAccount.credit(anount); } } } int fromHash = System.identityHashCode(fromAccount); int toHash = System.identityHashCode(toAccount); if (fromHash < toHash){ synchronized (fromAccount){ synchronized (toAccount) { new Helper().transfer(); } } } else if (fromHash > toHash){ synchronized (toAccount){ synchronized (fromAccount) { new Helper().transfer(); } } } else { synchronized (tieLock) { synchronized (fromAccount) { synchronized (toAccount) { new Helper().transfer(); } } } } }
3. 在協作對象之間發生的死鎖
class Taxi { private Point location, destination; private final Dispatcher dispatcher; public Taxi(Dispatcher dispatcher) { this.dispatcher = dispatcher; } public synchronized Point getLocation(){ return location; } public synchronized void setLocation(Point location){ this.location = location; if (location.equals(destination)){ dispatcher.notifyAvaliable(this); } } } class Dispatcher { private final Set<Taxi> taxis; private final Set<Taxi> avaliableTaxis; public Dispatcher(){ taxis = new HashSet<Taxi>(); avaliableTaxis = new HashSet<Taxi>(); } public synchronized void notifyAvaliable(Taxi taxi) { avaliableTaxis.add(taxi); } public synchronized Image getImage(){ Image image = new Image(); for (Taxi t :taxis){ image.drawMarker(t.getLocation()); } return image; } }
4. 開放調用 -- 待填充
5. 資源死鎖 外部鎖常被忽視而導致死鎖,比如數據庫的鎖
二、死鎖的避免與診斷
1. 支持定時的死鎖 存在一些預防死鎖的手段。比方Lock的tryLock,JDK 7中引入的Phaser等。
2. 通過線程轉儲信息來分析死鎖 通過Dump線程的StackTrace,比如linux下運行命令 kill -3 <pid>,或者jstack –l <pid>,或者使用Jconsole連接上去查看線程的StackTrace,由此來診斷死鎖問題。
三、其它活躍性危急
1. 饑餓 2. 糟糕的響應性 3. 活鎖四、鎖的使用
使用支持CAS的數據結構。避免使用鎖。如:AtomicXXX、ConcurrentMap、CopyOnWriteList、ConcurrentLinkedQueue 死鎖常常是無法全然避免的,鴕鳥策略被非常多基礎框架所採用。 存在檢測死鎖的辦法五、參考資料:
《溫紹錦 - Java並發程序設計教程》《Java並發編程實戰》第十章 避免活躍性危急 讀書筆記