一、活鎖定義(源自百度百科)
活鎖可以認爲是一種特殊的飢餓。 下面這個例子在有的文章裏面認爲是活鎖。實際上這只是一種飢餓。因爲沒有體現出“活”的特點。 假設事務T2再不斷的重複嘗試獲取鎖R,那麼這個就是活鎖。
如果事務T1封鎖了數據R,事務T2又請求封鎖R,於是T2等待。T3也請求封鎖R,當T1釋放了R上的封鎖後,系統首先批准了T3的請求,T2仍然等待。然後T4又請求封鎖R,當T3釋放了R上的封鎖之後,系統又批准了T4的請求......T2可能永遠等待。
活鎖應該是一系列進程在輪詢地等待某個不可能爲真的條件爲真。活鎖的時候進程是不會blocked,這會導致耗盡CPU資源。
二、活鎖的例子
1、單一實體的活鎖
例如線程從隊列中拿出一個任務來執行,如果任務執行失敗,那麼將任務重新加入隊列,繼續執行。假設任務總是執行失敗,或者某種依賴的條件總是不滿足,那麼線程一直在繁忙卻沒有任何結果。2、協同導致的活鎖
生活中的典型例子: 兩個人在窄路相遇,同時向一個方向避讓,然後又向另一個方向避讓,如此反覆。通信中也有類似的例子,多個用戶共享信道(最簡單的例子是大家都用對講機),同一時刻只能有一方發送信息。發送信號的用戶會進行衝突檢測, 如果發生衝突,就選擇避讓,然後再發送。 假設避讓算法不合理,就導致每次發送,都衝突,避讓後再發送,還是衝突。
計算機中的例子:兩個線程發生了某些條件的碰撞後重新執行,那麼如果再次嘗試後依然發生了碰撞,長此下去就有可能發生活鎖。
三、示例說明((下述的例子不一定就要去優化,只是直覺上的一種衝動))
private static short counter = (short) 0;
synchronized(Test.class) {
if (counter<0) counter=0;
return counter++;
}
}
int i = counter.getAndIncrement();
while (i >= Short.MAX_VALUE) {
counter.compareAndSet(i, 0);//------------------------------CAS指令1
i = counter.getAndIncrement();//-----------------------------CAS指令2
}
return (short)i;
}
四、活鎖的解決方法
1、解決協同活鎖的一種方案是調整重試機制。
比如引入一些隨機性。例如如果檢測到衝突,那麼就暫停隨機的一定時間進行重試。這回大大減少碰撞的可能性。2、另外爲了避免可能的死鎖,適當加入一定的重試次數也是有效的解決辦法。
比如約定重試機制避免再次衝突。 例如自動駕駛的防碰撞系統(假想的例子),可以根據序列號約定檢測到相撞風險時,序列號小的飛機朝上飛, 序列號大的飛機朝下飛。