为什么等待条件释放锁定但信号没有?

Jas*_*key 4 java concurrency multithreading locking monitor

我编写下面的代码来测试线程在等待Condition对象时何时处于唤醒状态.

  1. 但我发现打电话后我必须解锁signal().此方法不会释放锁定,而await()将释放此锁定.

这是来自条件#等待

与此条件关联的锁被原子释放,并且当前线程因线程调度而被禁用,并处于休眠状态,直到发生以下四种情况之一:

这是来自Conditon#signal

唤醒一个等待线程.

如果任何线程正在等待这种情况,则选择一个线程进行唤醒.然后该线程必须在从await返回之前重新获取锁.

但在我的代码中,这是不正确的,直到我们解锁.为什么这样设计?因为在我看来,当我们决定向其他人发出信号时,我们不应再持有锁,我错了吗?

  1. 既然我们可以做调用之间很多事情signalunlock,说我睡10秒,究竟是什么时候java的信号的其他线程?是否有另一个背景线程在我们signalunlock?之间工作?

      public class  WorkerThread extends Thread{    
        @Override
        public void run() {
        Monitor.lock.lock();
        while (!Monitor.isConditionTrue){
            try {
                Monitor.condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("THREAD ID "+this.getId()+"-------working --------");
        System.out.println("------singnall--------");
        Monitor.isConditionTrue=true;
        Monitor.condition.signal();
            try {
               Thread.sleep(3000);//here, the thread is sleeping while another thread is not awaken since the lock is not releases
               System.out.println("------unlock--------");
               Monitor.lock.unlock();//now the other thread is awaken, if I do not explicitly unlock , no thread will be awaken.
            } 
           catch (InterruptedException e) {
                e.printStackTrace();
           }
        }
    }
    
    
    public class Monitor {
        static ReentrantLock lock = new ReentrantLock();
        static Condition condition = lock.newCondition();
        static volatile boolean isConditionTrue = true;
    
        public static void main(String args[]) {
            Thread t1 = new WorkerThread();
            Thread t2 = new WorkerThread();
            t1.start();
            t2.start();
            Thread.sleep(2000);
            lock.lock();
            isConditionTrue=true;
            condition.signalAll();
            lock.unlock();
        }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)

OUTPUT:

THREAD ID 9-------working --------
------singnall--------
------unlock--------
THREAD ID 10-------working --------
------singnall--------
------unlock--------
Run Code Online (Sandbox Code Playgroud)

Mar*_*nik 8

你错过了这句话Contition#await:

在所有情况下,在此方法可以返回之前,当前线程必须重新获取与此条件关联的锁.当线程返回时,保证保持此锁定.

换句话说,您必须明确释放锁定await,就像使用signal.

为什么这个机制是合理的:如果你第一次释放锁,然后signal编辑,你就会对竞争条件开放,其他线程在释放锁和信号到达停放线程之间做出了改变.机制的工作方式,首先选择一个确定的线程被信号唤醒,然后它等待锁定,然后信号线程释放它,然后唤醒线程继续.

您可能会认为signal可以在内部完成所有这些,但随后:

  1. API会变得混乱:释放锁的方法不止一个;
  2. APi将变得更具限制性并且排除线程想要在释放锁之前做更多事情的任何用例,例如原子地发出更多信号.

  • 否则你不能让 `await` 工作,这就是原因。它在进行过程中在内部释放锁,并在稍后重新获取它。这就是“await”的本质。 (2认同)