2.1 時間
- 線程是個狀態(tài)機,其狀態(tài)的轉換稱為事件。
- 事件是瞬間發(fā)生的,我們假設不同的事件在不同的時間點發(fā)生。
- 事件間隔有重疊時,稱為 并發(fā)的。
2.2 臨界區(qū)
- 某個時刻僅能夠被一個線程執(zhí)行的代碼,稱為臨界區(qū)。
- 上面的特性,稱為 互斥。
-
+? 互斥:不同線程的臨界區(qū)之間沒有重疊。
+ 無死鎖:如果一個線程正在嘗試獲得一個鎖,那個總會成功的獲得這個鎖。
+ 無饑餓:每個試圖獲得鎖的線程最終都能成功。//無饑餓意味著無死鎖。
//無饑餓特性不保證線程在進入臨界區(qū)以前需要等待多長時間。
- 即使程序所使用的每個鎖都滿足無死鎖特性,該程序也可能死鎖。
2.3 雙線程解決方案
2.3.1 LockOne算法
LockOne算法的缺陷:**LockOne算法在交叉執(zhí)行的時候會出現(xiàn)死鎖。若事件writeA(flag[A] = true)與writeB(flag[B] = true)在事件readA(flag[B]==flase)和readB(flag[A]==false)之前發(fā)生,那么兩個線程都將陷入無窮等待。
2.3.2 LockTwo算法
LockTwo類存在的缺陷:當一個線程完全先于另一個線程執(zhí)行的時候就會出現(xiàn)死鎖。但是兩個線程并發(fā)地執(zhí)行,卻是成功的。由此,我們看到LockOne與LockTwo算法彼此互補,于是將兩者結合的算法Peterson算法實現(xiàn)了。
2.3.3 Peterson鎖
Peterson鎖算法://雙線程互斥算法
class Peterson implements Lock {
// thread-local index, 0 or 1
private volatile boolean[] flag = new boolean[2];
private volatile int victim;
public void lock() {
int me = ThreadID.get();
int he = 1 - me;
flag[me] = true;??????????? // I’m interested
victim = me;??????????????? // you go first
while (flag[he] && victim == me) {}; // wait
}
public void unlock() {
int me = ThreadID.get();
flag[me] = false;?????????? // I’m not interested
}
}
-? Peterson鎖是滿足互斥特性,是無饑餓,無死鎖的。
2.4 過濾鎖(分層策略)
算法代碼:
class Filter implements Lock {
int[] level;
int[] victim;
public Filter(int n) {
level = new int[n];
victim = new int[n]; // use 1..n-1
for (int i = 0; i < n; i++) {
level[i] = 0; //[1]
}
}
public void lock() {
int me = ThreadID.get();
for (int i = 1; i < n; i++) { //attempt level 1 //[2]
level[me] = i;
victim[i] = me;
// spin while conflicts exist
while ((?k != me) (level[k] >= i && victim[i] == me)) {}; //[3]
}
}
public void unlock() {
int me = ThreadID.get();
level[me] = 0;
}
}
說明:? - n 元整數(shù)組level [], level[A]的值表示線程A正在嘗試進入的層。
- 每個層都有一個victim[l] 域, 用來選出線程,“留守”本層。