Java线程wait() => 阻塞?

13

根据Java线程状态信息,调用wait()会使线程进入BLOCKED状态。然而,这段代码将导致(在调用后)线程进入WAITING状态。

class bThread extends Thread {
    public synchronized void run() {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

我是否有什么地方出错了?有人能向我解释一下这个行为吗?任何帮助都将不胜感激!


附注:您应该将等待调用与条件关联。 - stdout
6个回答

20
该线程在等待被通知,然后尝试重新进入同步区域并阻塞,直到所有其他线程离开。当线程调用Object.wait()方法时,它正在等待另一个线程调用该对象的Object.notify()或Object.notifyAll()方法。阻塞状态的线程正在等待监视锁定以便在调用Object.wait()之后重新进入同步块/方法。最后一部分是指线程尝试从wait()返回,但直到那时才会发生。

这是否意味着一个被阻塞的线程在循环中获取锁?也就是说,处于阻塞状态的线程会消耗CPU时间吗? - acerphenix
@user2807219:通常不会。线程将在保护同步区域的互斥锁的就绪队列中,就像您调用由另一个线程锁定的同步函数一样。锁竞争需要担心的主要成本通常是它强制程序上下文切换(即在CPU中存储和恢复运行线程的状态),这是相对昂贵的。 - Josef Grahn

13

监视器一次只能执行一个线程。假设您有T1-T10个线程,其中9个是BLOCKED,一个是RUNNABLE。每隔一段时间,监视器会选择一个新的线程来运行。当这种情况发生时,选择/当前线程(例如T1)从RUNNABLE变为BLOCKED。然后另一个线程,比方说T2,就从BLOCKED变为RUNNABLE,成为当前的线程。

当其中一个线程需要其他线程提供可用的信息时,您可以使用wait()。在这种情况下,该线程将被标记为WAITING,直到它被notify()唤醒为止。因此,在那之前,等待的线程将不会被监视器执行。例如,等到有箱子需要卸载。装箱子的家伙会在发生这种情况时通知我。

换句话说,BLOCKEDWAITING都是不活动线程的状态,但是WAITING线程必须先进入BLOCKED状态才能变为RUNNABLEWAITING线程“不希望”变为活动状态,而BLOCKED线程“想要”成为活动状态,但是由于还没有轮到它们,所以无法成为活动状态。

我想是这样的。


这个答案最好地解释了我想知道的内容。 - PhoenixPerson

4
你在哪里看到说那样的话了?
在你提供的同一页中,链接为thread.state,它明确指出:
Object.wait()后会处于WAITING状态
进入同步块前会处于BLOCKED状态

哦,我明白可能会让你感到困惑的地方了。“BLOCKED => 或在调用Object.wait后重新进入同步块/方法。”请注意“重新进入同步块”。 - Yoni Roit

2

等待是指它什么都不做。阻塞是指它试图重新启动但尚未被允许。


2

这里存在一些混淆的术语。 当线程在对象上调用wait时,它会进入WAIT状态。 当线程“等待”获取锁时,它们属于该锁的等待集,但它们处于BLOCKED状态。

虽然有点混淆,但总体还是有道理的!


0
提醒一下,您应该始终在 while 循环中调用 wait(),等待进入同步区域/临界区的条件。这是因为 Java 存在“虚假唤醒”(本质上,线程可能会在任何时刻无缘无故地被唤醒)。

这应该是一条评论。它与 OP 没有任何关系。 - darw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接