执行wait()后,如果线程未从其他线程收到通知,它会等待多长时间?

huangapple go评论117阅读模式
英文:

After executing wait(), how long does a thread wait if it does not get notified from other threads?

问题

在下面的示例中,由于主线程未从子线程得到通知,它应该永远等待。但实际上主线程正在执行,以下示例的输出是:

c
l
total: 19900

为什么主线程会被执行?

public class ThreadX extends Thread {
    static int total = 0;

    public void run() {
        synchronized (this) {
            for (int i = 0; i < 200; i++) {
                total = total + i;
            }
            System.out.println("c");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadX t = new ThreadX();

        t.start();
        synchronized (t) {
            t.wait();
            System.out.println("l");
        }

        System.out.println("total: " + total);
    }
}
英文:

In the below example, as the main-thread is not getting notified from the child thread, it should wait forever. But the main-thread is getting executed and the output of the below example is:

c
l
total: 19900

Why is the main-thread getting executed?

public class ThreadX extends Thread {
	static int total = 0;

	public void run() {
		synchronized (this) {
			for (int i = 0; i &lt; 200; i++) {
				total = total + i;
			}
			System.out.println(&quot;c&quot;);

		}
	}

	public static void main(String[] args) throws InterruptedException {
		ThreadX t = new ThreadX();

		t.start();
		synchronized (t) {
			t.wait();
			System.out.println(&quot;l&quot;);
		}

		System.out.println(&quot;total: &quot; + total);

	}
}

答案1

得分: 9

Answer to the question-body

查看 Thread#join(long)

> [...] 当线程终止时,将调用 this.notifyAll 方法。[...]

注意,Thread#join() 使用参数 0 调用该函数,意味着永远等待。

> [...] 超时值为 0 表示无限等待。

因此在你的情况下,t 在终止时只是调用了 notifyAll,这会通知正在等待 t 的主线程。


这种不直观的行为是他们在文档中写下以下内容的原因:

> 建议应用程序不要在 Thread 实例上使用 waitnotifynotifyAll

Answer to the question-title

查看 Object#wait(或JLS(17.2.1. Wait)):

> 线程可能会在没有收到通知、中断或超时的情况下被唤醒,这称为虚假唤醒。虽然这在实践中很少会发生,但应用程序必须通过测试应该导致线程被唤醒的条件,并在条件不满足时继续等待来防范这种情况。

因此,在Java中,线程可能随时被唤醒。虽然虚假唤醒不太可能发生,但确实有可能发生。

英文:

Answer to the question-body

Check out Thread#join(long):

> [...] As a thread terminates the this.notifyAll method is invoked. [...]

Notice that Thread#join() calls that function with 0, which means forever.

> [...] A timeout of 0 means to wait forever.

So in your case here t just calls notifyAll when it terminates, which notifies the main-thread that is waiting on t.


This unintuitive behaviour is the reason why they write the following in the documentation:

> It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

Answer to the question-title

Check out Object#wait (or JLS (17.2.1. Wait)):

> A thread can wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied.

So threads in Java can wake up at any time. A spurious wakeup is not very likely but it can happen.

huangapple
  • 本文由 发表于 2020年8月16日 10:32:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/63432582.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定