互斥鎖(Mutex,mutual exclusion)
概念
互斥鎖(Mutex,mutual exclusion的縮寫 )是一種用于實(shí)現(xiàn)臨界區(qū)保護(hù)的同步原語,目的是確保在任意時(shí)刻,只有一個(gè)線程或進(jìn)程能夠訪問特定的共享資源,防止數(shù)據(jù)競爭和不一致性 。臨界區(qū)是程序中訪問共享資源的代碼片段,線程在進(jìn)入臨界區(qū)前獲取互斥鎖,退出時(shí)釋放鎖,以此保證同一時(shí)間只有一個(gè)線程能執(zhí)行該代碼段。
操作
- 鎖定(Lock):線程進(jìn)入臨界區(qū)前嘗試獲取互斥鎖。若鎖已被其他線程持有,當(dāng)前線程將被阻塞,直到鎖可用。
- 解鎖(Unlock):線程退出臨界區(qū)后釋放持有的互斥鎖,使其他等待線程可獲取該鎖。
實(shí)現(xiàn)方式
- 硬件實(shí)現(xiàn):
- 在單處理器系統(tǒng)中,可通過關(guān)閉中斷防止上下文切換,確保臨界區(qū)操作的原子性,但此方法不適用于多處理器系統(tǒng)。
- 在多處理器環(huán)境下,常利用原子操作,如測試并設(shè)置(Test - and - Set)或比較并交換(Compare - and - Swap)實(shí)現(xiàn)互斥鎖。這些操作由硬件支持,能在一個(gè)原子操作中完成鎖狀態(tài)的檢查和設(shè)置。
- 軟件實(shí)現(xiàn):缺乏硬件支持時(shí),可使用軟件算法實(shí)現(xiàn)互斥鎖,如Dekker算法和Peterson算法 。但這些算法需頻繁檢查共享變量狀態(tài),可能導(dǎo)致忙等待,浪費(fèi)CPU資源。
使用注意事項(xiàng)
- 死鎖:多個(gè)線程若以不同順序獲取多個(gè)鎖,可能導(dǎo)致死鎖。比如線程A持有鎖1等待鎖2,線程B持有鎖2等待鎖1,雙方都無法繼續(xù)執(zhí)行。避免死鎖可確保所有線程按相同順序獲取鎖,或采用嘗試鎖定機(jī)制,無法獲取鎖時(shí)采取適當(dāng)措施。
- 優(yōu)先級反轉(zhuǎn):高優(yōu)先級線程等待低優(yōu)先級線程釋放鎖,會使系統(tǒng)性能下降??墒褂脙?yōu)先級繼承協(xié)議,讓低優(yōu)先級線程持有鎖時(shí)臨時(shí)提升優(yōu)先級。
- 鎖的粒度:鎖粒度過大降低系統(tǒng)并發(fā)性能,粒度過小則增加鎖管理開銷,需依具體情況選擇合適粒度。
Java代碼示例
在Java中,可通過java.util.concurrent.locks.ReentrantLock
類實(shí)現(xiàn)互斥鎖功能,示例如下:
import java.util.concurrent.locks.ReentrantLock;
class SharedResource {
private int count = 0;
private ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock(); // 加鎖
try {
count++;
} finally {
lock.unlock(); // 解鎖
}
}
public int getCount() {
return count;
}
}
class MyThread extends Thread {
private SharedResource sharedResource;
MyThread(SharedResource sharedResource) {
this.sharedResource = sharedResource;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
sharedResource.increment();
}
}
}
public class MutexExample {
public static void main(String[] args) throws InterruptedException {
SharedResource sharedResource = new SharedResource();
MyThread thread1 = new MyThread(sharedResource);
MyThread thread2 = new MyThread(sharedResource);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Final count: " + sharedResource.getCount());
}
}
上述代碼中,ReentrantLock
實(shí)現(xiàn)互斥鎖。SharedResource
類有共享變量count
,increment
方法中先調(diào)用lock.lock()
加鎖,確保同一時(shí)刻只有一個(gè)線程能執(zhí)行count++
操作,操作完成后在finally
塊中用lock.unlock()
解鎖,保證鎖一定能被釋放。MyThread
類的線程對共享資源進(jìn)行操作,main
方法創(chuàng)建兩個(gè)線程并啟動,最后輸出共享變量最終值。