两个线程同时执行同步块

Posted

技术标签:

【中文标题】两个线程同时执行同步块【英文标题】:Two threads executing synchronized block simultaneously 【发布时间】:2019-02-27 20:21:18 【问题描述】:

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

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

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

预期输出:

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

实际输出:

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) 
        
    

【问题讨论】:

无关:请停止使用Date 类。 java.time 包太棒了。 【参考方案1】:

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

[...] 该方法使当前线程(称为 T)将自己置于该对象的等待集中,然后放弃对该对象的所有同步声明。 [...]

【讨论】:

【参考方案2】:

使用

Thread.sleep(5000);

JavaDocs for Thread.sleep:

使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。线程不会失去对任何监视器的所有权。

【讨论】:

【参考方案3】:

Oracle Tutorials 的以下引用解释了这种情况:

wait被调用时,线程释放锁并挂起 执行。

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

【讨论】:

以上是关于两个线程同时执行同步块的主要内容,如果未能解决你的问题,请参考以下文章

同步锁之lock

多线程同步的五种方法

java多线程——锁机制synchronized(同步方法)

多个线程不能同时进入一个同步块吗?

2.2.2synchronized同步代码块的使用

java 多线程同步常用的3种方法