亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么信號量工作而 ReentrantLock 不工作?

為什么信號量工作而 ReentrantLock 不工作?

炎炎設計 2023-03-23 16:24:19
我正在嘗試 Leetcode 中的一個簡單的并發問題。我在大學里非常簡要地研究過這個主題,但沒有使用 Java API。似乎我不能在ReentrantLock不Lock遇到IllegalMonitorStateException. 然而 a Semaphore(這似乎有點矯枉過正,因為我只需要使用二進制值)似乎工作正常。為什么是這樣?二進制信號量與 ReentrantLock建議(如果我理解正確的話)二進制鎖只能由獲取它的線程釋放,這可能是我的問題的根源,因為我在下面的代碼中的構造函數中獲取它們。有沒有其他自然的方法可以使用鎖/不使用信號量來解決這個問題?Lock帶有引發 s 的代碼IllegalMonitorStateException:import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;class Foo {    private Lock printedFirst;    private Lock printedSecond;    public Foo() {        this.printedFirst = new ReentrantLock();        this.printedSecond = new ReentrantLock();        printedFirst.lock();        printedSecond.lock();    }    public void firsSemaphore帶有按預期工作的 s 的代碼:import java.util.concurrent.Semaphore;class Foo {    private Semaphore printedFirst;    private Semaphore printedSecond;    public Foo() {        this.printedFirst = new Semaphore(0);        this.printedSecond = new Semaphore(0);    }    public void first(Runnable printFirst) throws InterruptedException {        printFirst.run();        printedFirst.release();    }    public void second(Runnable printSecond) throws InterruptedException {        printedFirst.acquire();        try {            printSecond.run();        } finally {            printedSecond.release();        }    }    public void third(Runnable printThird) throws InterruptedException {        printedSecond.acquire();        try {            printThird.run();        } finally {}    }}t(Runnable printFirst) throws InterruptedException {        printFirst.run();        printedFirst.unlock();    }    public void second(Runnable printSecond) throws InterruptedException {        printedFirst.lock();        try {            printSecond.run();        } finally {            printedSecond.unlock();        }    }    public void third(Runnable printThird) throws InterruptedException {        printedSecond.lock();        try {            printThird.run();        } finally {}    }}
查看完整描述

3 回答

?
蝴蝶不菲

TA貢獻1810條經驗 獲得超4個贊

同步有兩個主要用例:資源訪問和事件傳遞。您試圖解決的并發問題需要事件傳遞:第二個線程等待第一個線程的信號,第三個線程等待第二個線程的信號。信號,我的意思是,是空事件,它們帶有事件已經發生的事實,沒有任何額外的細節。

Semaphores 非常適合信號傳遞(盡管也可用于資源訪問)。ReentrantLocks 是為資源訪問而設計的。從技術上講,任何事件傳遞機制都是建立在資源訪問之上的。因此您可以使用ReentrantLocks 進行信號傳遞,但它需要一些額外的編程(在@billie 的回答中演示)。


查看完整回答
反對 回復 2023-03-23
?
森林海

TA貢獻2011條經驗 獲得超2個贊

正如您所發現的,信號量易于實現和推理 - 獲取鎖定、執行操作、釋放鎖定。ReentrantLocks 是不同的,旨在服務于您發布的示例中不存在的更復雜的目的。是的,ReentrantLocks 由單個線程擁有,只能由該線程釋放。

如果您的目標是生成供兩個線程使用的受保護代碼,則使用信號量會比 ReentrantLock 更簡單且更不容易出錯。但是,如果您的目標是了解 ReentrantLocks 的工作原理(或者如果您的用例以某種方式更適合 ReentrantLocks 而不是從上面的示例中清楚地看到),我鼓勵您閱讀 Javadoc - https://docs.oracle.com/ javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html - 它包含有關如何使用它們以及它們的行為方式的有用信息。


查看完整回答
反對 回復 2023-03-23
?
紅糖糍粑

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


作為旁注,您可以通過為每個操作要求/釋放多個許可來僅使用一個信號量來完成此操作。


查看完整回答
反對 回復 2023-03-23
  • 3 回答
  • 0 關注
  • 116 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號