0%

互斥锁

文章字数:437,阅读全文大约需要1分钟

互斥锁是最普遍的多线程锁,并发编程除了考虑运行结果的正确之外,还需要线程无死锁(线程永久停滞),无饥饿(部分线程永远拿不到执行权限)

特性

  1. 互斥: 保证互斥行的专有名词是临界区,临界区内的代码在某个时刻只能被一个线程执行。即被锁保护的代码区域。
  2. 无死锁: 不会永久停滞
  3. 无饥饿: 不会部分永久停滞
1
2
3
4
5
6
7
/**
* 一个锁的基本形态
**/
interface Lock {
public void lock();//锁定
public void unlock();//解锁
}

注意事项

  1. 使用方式
1
2
3
4
5
6
7
//在try之前就需要获取锁,避免发生异常时未获取到锁就执行解锁。
mutex.lock();
try{
...临界区
}finally{
mutex.unlock()
}
  1. 减少互斥锁粒度: 锁粒度越小,程序执行是需要串行执行的工作就会越少。就可以更充分利用多处理器并行处理的优势。

  2. 进来不用锁: 减少串行执行工作量。

互斥锁示例

《多处理器编程的艺术》中Peterson算法,保证两个线程使用锁时互斥,无死锁,无饥饿。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

class Peterson implements Lock {
private boolean[] flag = new boolean[2];
private int victim;
public void lock(){
int i = ThreadID.get();
int j = 1 - i; //因为只有两个,所以1-i就是另一个线程的id
flag[i]= true; // 标记当前线程需要获取锁
victim = i; // 并发时后改变这个值的线程自旋(保证早获取的执行,防止饥饿)
while(flag[j] && victim == i){} // 当另一个锁需要执行,自己又获取的晚,那么等待另一个执行完。
}

public void unlock(){
int i = ThreadID.get();
flag[i] = false;
}

}