两个线程同时执行同步块

Two threads executing synchronized block simultaneously

下面是 Thread 进入同步块,等待 5 秒然后退出的代码。我同时启动了两个 Thread 个实例。

预期其中一个线程将拥有同步对象上的锁,而另一个将等待。 5秒后,当锁拥有者退出时,等待线程就会执行。

但是,实际上,两个线程都在同时执行同步块,同时退出。

Expected Output:

Thread-X <timeX> received the lock.
Thread-X <timeX+5s> exiting...
Thread-Y <timeY> received the lock.
Thread-Y <timeY+5s> exiting...

Actual Output:

Thread-X <time> received the lock.
Thread-Y <time> received the lock.
Thread-X <time+5s> exiting...
Thread-Y <time+5s> exiting...

我是不是漏掉了什么?

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test2 {
public static void main(String[] args) {
    MyRunnable m = new MyRunnable();
    Thread t = new Thread(m);
    Thread t1 = new Thread(m);
    t.start();
    t1.start();
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        synchronized (this) {
            try {
                SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
                Date date = new Date(System.currentTimeMillis());
                System.out.println(Thread.currentThread().getName() + " " + formatter.format(date) + " received the lock.");
                wait(5000);
                date = new Date(System.currentTimeMillis());
                System.out.println(Thread.currentThread().getName() + " " + formatter.format(date) + " exiting...");
            } catch(InterruptedException ie) {}
        }
    }
}

答案在 java.lang.Object.wait(long) 中,其文档说:

[...] This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. [...]

使用

Thread.sleep(5000);

JavaDocs for Thread.sleep:

Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.

以下来自 Oracle Tutorials 的引述解释了这种情况:

When wait is invoked, the thread releases the lock and suspends execution.

此外,只有一个线程可以执行由同一对象保护的 synchronized 块!在您的示例中调用 wait 会释放锁,从而允许另一个线程获取锁。