Peterson lock是并发中实现两个线程互斥的经典算法
// 假设两个thread的id分别为0,1
public class Peterson {
private volatile boolean[] flag = new boolean[2];
private volatile int last; // 声明为volatile保证last在线程间的可见性
public void lock() {
int i = Thread.currentThread().getId();
int j = 1-i;
flag[i] = true; [1] // flag[j]==true; [4]
last = i; [2] // last = j; [5]
while(flag[j] && i == last){} //[3] // [6]
}
public void unlock() {
int i = Thread.currentThread().getId();
flag[i] = false;
}
}
该算法实现互斥的关键是last无法同时即等于i又等于j(由volatile保证)。
假设有线程A与线程B,[1][2][3]为线程A的执行步骤,[4][5][6]为线程B的执行步骤,若线程A与线程B同时调用lock(),对于线程A可见的执行顺序有:
- [2]->[5]->[3],此时对于线程A有 (flag[j]==true && i==last)为false 线程A往下执行,对于线程B(flag[i]==true && j==last)为true,线程B在[6]处死循环知道线程A调用unlock()。
[2]->[3]->[5],此时对于线程A若[4]先于[2][3]执行则有 (flag[j]==true && i==last)为true,线程A死循环,对于线程B有(flag[i]==true && j==last)为false线程B往下执行;若[4]后于[2][3]执行则有(flag[j]==false && i==last)为false,线程A往下执行,对于线程B有(flag[i]==true && j==last)为true,死循环。
此外,通过将last声明为volatile防止了[1][2]的重排序。