2008-10-22 68 views
33

有人在工作时只是被问到了在一个同步内包装等待的原因。任何人都可以解释线程监视器并等待吗?

老实说我看不到推理。我明白javadocs说什么 - 线程需要是对象监视器的所有者,但为什么?它阻止了什么问题? (如果它的实际需要,为什么不能等待方法获取显示器本身?)

我正在寻找一个相当深入的原因,或者一个到文章的参考。我无法在快速的谷歌找到一个。

哦,还有,thread.sleep怎么比较呢?

编辑:伟大的答案 - 我真的希望我可以选择多个答案,因为他们都帮助我了解发生了什么。

回答

3

如果对象不拥有对象监视器时,它调用的Object.wait(),这将无法直到显示器被释放访问对象设置一个通知监听器。相反,它将被视为尝试访问同步对象上的方法的线程。

,或者换一种说法,有没有什么区别:

public void doStuffOnThisObject() 

和下面的方法:

public void wait() 

这两种方法都将被阻止,直到对象监视器被释放。这是Java中的一项功能,可防止多个线程更新对象的状态。它只是对wait()方法产生意想不到的后果。

据推测,wait()方法是不同步的,因为这可能造成的情况下的线程具有对象的多个锁。 (有关这方面的更多信息,请参见Java Language Specifications/Locking。)多重锁是一个问题,因为wait()方法将只撤销一个锁。如果该方法是同步的,它将保证只有方法的锁将被撤消,同时仍然留下潜在的外部锁。这会在代码中创建一个死锁状态。

要回答你的问题了Thread.sleep(),Thread.sleep()方法并不能保证你正在等待被满足,无论条件。使用Object.wait()和Object.notify()允许程序员手动实现阻塞。一旦发送通知已满足条件,线程就会解锁。例如从磁盘读取已完成,数据可由线程处理。 Thread.sleep()会要求程序员轮询是否满足条件,如果没有满足则返回到休眠状态。

+0

我明白同步。问题是,为什么object.wait()需要拥有监视器,或者为什么不能将该监视器的获取封装在对象中。wait()方法(或者Thread.sleep()是做什么的?) – 2008-10-22 16:06:03

+0

对不起,我误解了。答案已经更新。是否更好地回答你的问题? – 64BitBob 2008-10-22 16:30:20

4

它需要自己的显示器,因为等待的目的,()是释放监视器,并让其他线程获得对监视器做自己的处理。这些方法(等待/通知)的目的是协调对两个线程之间需要彼此执行某些功能的同步代码块的访问。这不仅仅是确保访问数据结构是线程安全的问题,而且是为了协调多个线程之间的事件。

一个典型的例子是,其中一个线程将数据推送到一个队列一个生产者/消费者情况下,而另一个线程消耗的数据。消费线程将始终要求监视器访问队列,但一旦队列为空时将释放监视器。当消费者不再处理时,生产者线程将只能访问写入线程。一旦它将更多数据推入队列中,它就会通知消费者线程,因此它可以重新获得监视器并再次访问队列。

5

等待放弃显示器,所以你必须让它放弃。通知也必须有显示器。

要做到这一点的主要原因是为了确保在从wait()返回时拥有监视器 - 通常,您正在使用wait/notify协议来保护某个共享资源,并且希望它等待返回时可以安全地触摸它。与通知相同 - 通常情况下,您正在更改某些内容,然后调用notify() - 您想要监视器,进行更改并调用notify()。

如果你犯了这样一个功能:

public void synchWait() { 
    syncronized { wait(); } 
} 

你不会显示器时,等待返回 - 你可以得到它,但你可能无法得到它旁边。

2

以下是我对限制实际上是一项要求的理解。我基于一个C++监视器的实现,我通过结合互斥和条件变量重新做了一段时间。

互斥+ condition_variable =监视器系统,所述wait调用设置条件变量进入等待状态并释放互斥。条件变量是共享状态,所以需要锁定它以避免想要等待的线程与想要通知的线程之间的竞争条件。而不是引入另一个互斥锁来锁定其状态,而是使用现有的互斥锁。在Java中,当即将到来的线程拥有监视器时,互斥锁被正确锁定。

13

很多很好的答案已经在这里。但在这里只想提一下,使用wait()时,其他必须做的是在一个循环中执行它,这取决于您正在等待的情况,以防您发现虚假唤醒,这是我的经验。

要等待另一个线程来改变一个条件为真,并通知:

synchronized(o) { 
    while(! checkCondition()) { 
    o.wait(); 
    } 
} 

当然,这些天,我建议只使用新条件的对象,因为它是更清晰,具有更多的功能(比如每个锁允许多个条件,能够检查等待队列长度,更灵活的时间表/中断等)。

Lock lock = new ReentrantLock(); 
Condition condition = lock.newCondition(); 
lock.lock(); 
try { 
    while (! checkCondition()) { 
    condition.await(); 
    } 
} finally { 
    lock.unlock(); 
} 

}

2

如果有一个条件天色等待做是说一个队列为空。

If(queue is empty) 
    queue.wait(); 

让我们假设队列为空。 如果当前线程在检查队列之后抢先,那么如果另一个线程添加了几个元素到队列中,则当前线程将不知道并且将等待 状态。这是错误的。 所以我们应该有类似

Synchornized(queue) 
{ 
    if(queue is empty) 
      queue.wait(); 
} 

现在让我们考虑一下,如果他们取得等待本身同步。正如其中一条评论所述,它只释放一个锁。这意味着如果wait()在上面的代码中被同步,则只有一个锁被释放。意味着当前线程将等待队列的锁定。

相关问题