3 回答

TA貢獻1810條經驗 獲得超4個贊
同步有兩個主要用例:資源訪問和事件傳遞。您試圖解決的并發問題需要事件傳遞:第二個線程等待第一個線程的信號,第三個線程等待第二個線程的信號。信號,我的意思是,是空事件,它們帶有事件已經發生的事實,沒有任何額外的細節。
Semaphore
s 非常適合信號傳遞(盡管也可用于資源訪問)。ReentrantLock
s 是為資源訪問而設計的。從技術上講,任何事件傳遞機制都是建立在資源訪問之上的。因此您可以使用ReentrantLock
s 進行信號傳遞,但它需要一些額外的編程(在@billie 的回答中演示)。

TA貢獻2011條經驗 獲得超2個贊
正如您所發現的,信號量易于實現和推理 - 獲取鎖定、執行操作、釋放鎖定。ReentrantLocks 是不同的,旨在服務于您發布的示例中不存在的更復雜的目的。是的,ReentrantLocks 由單個線程擁有,只能由該線程釋放。
如果您的目標是生成供兩個線程使用的受保護代碼,則使用信號量會比 ReentrantLock 更簡單且更不容易出錯。但是,如果您的目標是了解 ReentrantLocks 的工作原理(或者如果您的用例以某種方式更適合 ReentrantLocks 而不是從上面的示例中清楚地看到),我鼓勵您閱讀 Javadoc - https://docs.oracle.com/ javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html - 它包含有關如何使用它們以及它們的行為方式的有用信息。

TA貢獻1815條經驗 獲得超6個贊
ReentrantLock解鎖狀態的API將拋出IllegalMonitorStateException - if the current thread does not hold this lock,在您的代碼中,這看起來正是正在發生的事情。
這不是ReentrantLocks 的正常用法,但是如果您無論如何都想使用它們來完成此操作,那么一種方法可能是使用以下方法跟蹤狀態:
private volatile int tracker = 0;
private Lock lock= new ReentrantLock();
public void first(Runnable printFirst) throws InterruptedException {
lock.lock();
try {
printFirst.run();
tracker++;
} finally {
lock.unlock();
}
}
public void second(Runnable printSecond) throws InterruptedException {
while(!Thread.currentThread().isInterrupted()) {
lock.lock();
try {
if (tracker == 1) {
printSecond.run();
tracker++;
break;
}
} finally {
lock.unlock();
}
Thread.yield();
}
}
public void third(Runnable printThird) throws InterruptedException {
while(!Thread.currentThread().isInterrupted()) {
lock.lock();
try {
if (tracker == 2) {
printThird.run();
tracker++;
break;
}
} finally {
lock.unlock();
}
Thread.yield();
}
}
如果您希望它更高效(減少第二個/第三個函數的處理),那么您可能需要查看類似Condition https://docs.oracle.com/javase/7/docs/api/java/util/concurrent的內容/鎖/Condition.html
作為旁注,您可以通過為每個操作要求/釋放多個許可來僅使用一個信號量來完成此操作。
添加回答
舉報