java condition.await()直到其锁定呼叫Unlock()才发出信号()

发布于 2025-02-13 12:06:34 字数 3201 浏览 0 评论 0原文

Java Doc for condition.await()

与此情况关联的锁被原子释放,并且 当前线程被禁用于线程调度目的,并且 处于休眠状态,直到四件事发生:

  • 其他一些线程调用信号此条件的方法

...

我写了一个测试程序,以查看,thread-1呼叫之后并被阻止,thread-2呼叫code> condition.signal()

我希望Thread-1应立即从等待()返回并继续。

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.*;
public class TestThreadCondition {
    public static void main(String[] args) throws InterruptedException {
        Lock rLock = new ReentrantLock();
        Condition cond = rLock.newCondition();
        AtomicBoolean aBool = new AtomicBoolean(true);
        Thread t1 = new Thread(new Runnable() {
            @Override public void run() {
                try {
                    rLock.lock();
                    System.out.println("(Step 1) Thread 1 locks and sleeps 1s");
                    Thread.sleep(1000);
                    while (aBool.get()) {
                        System.out.println("(Step 3) Thread 1 enters while loop");
                        cond.await();
                        System.out.println("(Step 5) Thread 1 got signal");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    rLock.unlock();
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override public void run() {
                try {
                    Thread.sleep(300);
                    System.out.println("(Step 2) Thread 2 also requires lock, blocked");
                    rLock.lock();
                    System.out.println("(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal");
                    cond.signal(); // I hope this would signal "t1" and t1 will enter (Step 5) immediately.
                    System.out.println("(Step 6) Thread 2 sleeps 3s and set aBool");
                    Thread.sleep(3000);
                    aBool.compareAndSet(true, false);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    rLock.unlock();
                    System.out.println("(Step 7) unlock");
                }
            }
        });
        t2.start();
        t1.join();
        t2.join();
    }
}

期望该程序将运行和打印,

Step1->Step2->Step3->Step4->Step5->Step6->Step7.

实际结果是:

(Step 1) Thread 1 locks and sleeps 1s
(Step 2) Thread 2 also requires lock, blocked
(Step 3) Thread 1 enters while loop
(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal
(Step 6) Thread 2 sleeps 3s and set aBool
(Step 7) unlock
(Step 5) Thread 1 got signal

步骤5 是在 step6 之后执行的。和 step7 。在Thread-1,cond.await()中,当Thread-2称为cond.signal时,它都不会唤醒,并且它会阻止thread-thread-2 nater-2 nater-nater-2 nater-thread-2 nater-nater-2 nater-2 nater-2 nater-nater-2 > rlock.unlock()。

正如我一开始所说,这似乎与Javadoc的解释冲突。如何了解我的代码的行为?

Java doc for Condition.await():

The lock associated with this Condition is atomically released and the
current thread becomes disabled for thread scheduling purposes and
lies dormant until one of four things happens:

  • Some other thread invokes the signal method for this Condition

...

I wrote a test program to see, after Thread-1 calls Condition.await() and gets blocked, Thread-2 calls Condition.signal().

I expect Thread-1 should return immediately from await() and continue.

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.*;
public class TestThreadCondition {
    public static void main(String[] args) throws InterruptedException {
        Lock rLock = new ReentrantLock();
        Condition cond = rLock.newCondition();
        AtomicBoolean aBool = new AtomicBoolean(true);
        Thread t1 = new Thread(new Runnable() {
            @Override public void run() {
                try {
                    rLock.lock();
                    System.out.println("(Step 1) Thread 1 locks and sleeps 1s");
                    Thread.sleep(1000);
                    while (aBool.get()) {
                        System.out.println("(Step 3) Thread 1 enters while loop");
                        cond.await();
                        System.out.println("(Step 5) Thread 1 got signal");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    rLock.unlock();
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override public void run() {
                try {
                    Thread.sleep(300);
                    System.out.println("(Step 2) Thread 2 also requires lock, blocked");
                    rLock.lock();
                    System.out.println("(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal");
                    cond.signal(); // I hope this would signal "t1" and t1 will enter (Step 5) immediately.
                    System.out.println("(Step 6) Thread 2 sleeps 3s and set aBool");
                    Thread.sleep(3000);
                    aBool.compareAndSet(true, false);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    rLock.unlock();
                    System.out.println("(Step 7) unlock");
                }
            }
        });
        t2.start();
        t1.join();
        t2.join();
    }
}

I expected that this program will run and print

Step1->Step2->Step3->Step4->Step5->Step6->Step7.

But the actual result was:

(Step 1) Thread 1 locks and sleeps 1s
(Step 2) Thread 2 also requires lock, blocked
(Step 3) Thread 1 enters while loop
(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal
(Step 6) Thread 2 sleeps 3s and set aBool
(Step 7) unlock
(Step 5) Thread 1 got signal

The Step 5 was executed after Step6 and Step7. It looks like that in Thread-1, cond.await() was not awaken when Thread-2 called cond.signal, and it blocks until Thread-2 called rLock.unlock().

This seems conflicts with the Javadoc's explanation, as I stated at the beginning. How to understand the behavior of my code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月光色 2025-02-20 12:06:34

在您的代码打印时,

(Step 5) Thread 1 got signal

Thread1已经退出了等待方法。如果没有已经获得锁定,就不可能走那么远。因此,如果另一个线程仍然有锁定,那自然不会发生。

因此,您的代码不是一个很好的测试,我们不知道信号是否已延迟到锁定为止,或者信号是否比该信号更早发生,并且thread1被唤醒,但正在阻止锁定。

在与内在锁的可比较情况下,它在Apidoc中拼写出来,该锁定通知将延迟,直到通知线程释放其锁定为止。无论如何,等待线程直到那时才能采取行动。如果在这里发生同样的情况,那就不足为奇了。
在任何情况下,爪哇省都没有矛盾,醒来并获得锁定是两种不同的事情。

At the time your code prints

(Step 5) Thread 1 got signal

Thread1 has already exited the await method. It cannot have gotten that far without already having acquired the lock. So naturally that can't happen if another thread still has the lock.

So your code isn't a good test, we don't know from it whether the signal was delayed until the lock was released, or if the signal occurred earlier than that and thread1 was woken up but was blocking on getting the lock.

In the comparable situation with intrinsic locks it is spelled out in the apidoc that notify is delayed until the notifying thread releases its lock. The waiting thread can't act until then anyway. If that same situation occurs here that would not be surprising.
There isn't a contradiction in the javadoc in any case, waking up and acquiring the lock are two different things.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文