为什么Lock条件等待必须持有锁

我对此表示怀疑,在Java语言中,我们需要保持锁定,然后再等待满足某些条件。

例如,int java monitor lock:

synchronized(lock){ System.out.println("before lock ..."); lock.wait(); System.out.println("after lock ..."); } 

或者是黄色的工具。

 Lock lock = new ReentrantLock(); Condition cond = lock.newCondition(); lock.lock(); try{ System.out.println("before condition ..."); cond.await(); System.out.println("after condition ..."); }catch(Exception e){ e.printStackTrace(); }finally{ lock.unlock(); } 

所以,为什么我们不能等待,而不是锁定?

如果只是因为Java,其他语言的工作有所不同?

我希望你能在设计之后解释原因,但不仅仅是JAVA-SPEC的定义。

想象一下,你有一些线程可能需要等待的东西。 也许你有一个队列,一个线程需要等到队列中有东西才能处理它。 队列必须是线程安全的,因此必须通过锁保护。 您可以编写以下代码:

  1. 获得锁。
  2. 检查队列是否为空。
  3. 如果队列为空,请等待将某些内容放在队列中。

糟糕,这是行不通的。 我们保持对队列的锁定,那么另一个线程如何在其上放置一些东西呢? 让我们再试一次:

  1. 获得锁。
  2. 检查队列是否为空。
  3. 如果队列为空,请释放锁并等待将某些内容放在队列中。

哎呀,现在我们还有问题。 如果在我们释放锁之后但在等待将某些东西放在队列之前,会有什么东西放在队列中呢? 在那种情况下,我们将等待已经发生的事情。

存在条件变量来解决这个确切的问题。 他们有一个关闭此窗口的primefaces“解锁和等待”操作。

因此,等待必须持有锁,否则将无法确保您不等待已经发生的事情。 您必须持有锁以防止另一个线程与您的等待竞争。

那么,我们还在等什么呢? 我们正在等待条件成为现实。 另一个线程将使条件成立,然后通知等待的线程。

在进入等待之前,我们必须检查条件是否为假; 这个检查和等待必须是primefaces的 ,即在同一个锁下。 否则,如果我们在条件已经为真的情况下进入等待,我们可能永远不会被唤醒。

因此,在调用wait()之前必须已获取锁定

 synchronized(lock) { if(!condition) lock.wait(); 

如果wait()自动并以静默方式获取锁定,则很多错误将无法检测到。


wait()唤醒后,我们必须再次检查条件 – 不能保证条件必须在这里变为真(出于很多原因 – 虚假唤醒;超时,中断,多个服务员,多个条件)

 synchronized(lock) { if(!condition) lock.wait(); if(!condition) // check again ... 

通常,如果条件仍为假,我们将再次等待。 因此典型的模式是

  while(!condition) lock.wait(); 

但也有一些我们不想再等待的情况。


有没有合法的用例,裸等待/通知有意义?

 synchronized(lock){ lock.wait(); } 

当然; 一个应用程序可以用裸等待/通知组成,具有明确定义的行为; 可以认为这是理想的行为; 这是该行为的最佳实现。

但是,这不是典型的使用模式,并且没有理由在API设计中考虑它。

请参阅条件文档。

条件类似于对象的等待池或等待集,它取代了对象监视器方法(wait,notify和notifyAll)的使用。 条件允许一个线程暂停执行(“等待”),直到另一个线程通知某个状态条件现在可能为真。 Condition实例本质上绑定到锁,就像Object监视器方法需要共享对象的锁等待或通知一样。 因此,在对条件调用await()之前,线程必须已锁定用于生成条件的Lock对象。 调用await()方法时,将释放与条件关联的锁。

如果线程只是在等待信号继续进行,那么还有其他机制可以做到这一点。 据推测,有一些状态受锁的保护,线程正在等待操作并满足某些条件。 为了正确保护该状态,线程应该在等待条件之前和之后具有锁定,因此需要获取锁定是有意义的。

简单的答案是因为否则您将获得在Object.wait javadoc中指定的IllegalMonitorStateException。 在内部,Java中的同步使用底层操作系统机制。 所以它不仅仅是Java。