当前位置: 首页 > 知识库问答 >
问题:

关于多线程Java两个问题使用通知()方法

梁渊
2023-03-14

代码:

public class NotifyAndWaitTest2 implements Runnable {
    public int i = 0;
    public Object lock;
    public SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");

    public NotifyAndWaitTest2(Object o) {
        this.lock = o;
    }

    @Override
    public void run() {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " enter the SYNCHRONIZED block --- "+ sdf.format(new Date()));
            try {
                while (i < 9) {
                    Thread.sleep(500);
                    lock.notify();
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " say:" + i++ + " --- " + sdf.format(new Date()));
                }
                lock.notify();
                return;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Object lock = new Object();
        NotifyAndWaitTest2 test = new NotifyAndWaitTest2(lock);
        Thread t1 = new Thread(test,"Thread A");
        Thread t2 = new Thread(test,"Thread B");
        Thread t3 = new Thread(test,"Thread C");
        Thread t4 = new Thread(test,"Thread D");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

结果:

Thread A enter the SYNCHRONIZED block --- 10:47:07.242
Thread B enter the SYNCHRONIZED block --- 10:47:07.743
Thread C enter the SYNCHRONIZED block --- 10:47:08.243
Thread D enter the SYNCHRONIZED block --- 10:47:08.743
Thread C say:0 --- 10:47:09.243
Thread D say:1 --- 10:47:09.744
Thread C say:2 --- 10:47:10.244
Thread D say:3 --- 10:47:10.744
Thread C say:4 --- 10:47:11.245
Thread D say:5 --- 10:47:11.745
Thread C say:6 --- 10:47:12.246
Thread D say:7 --- 10:47:12.746
Thread C say:8 --- 10:47:13.247
Thread D say:9 --- 10:47:13.247
Thread B say:10 --- 10:47:13.247
Thread A say:11 --- 10:47:13.247

代码在jdk1.7和jdk1.8中执行相同的结果。

我的问题:

> 线程 A 和线程 B 进入

  • SYNCHRONIZED 块并调用 wait() 方法后,为什么线程 C 和线程 D 进入而不是线程 A 说 i,然后线程 B 说 i?输入同步块的优先级是否高于刚刚调用 wait() 方法的线程?

    为什么调用通知()方法只是唤醒调用等待()方法的最后一个线程?就像线程C和线程D一样,相互通知并相互等待,为什么没有任何其他等待线程?比如线程A和线程B。

    我觉得应该是随机的,比如

    Thread A enter the SYNCHRONIZED block
    Thread B enter the SYNCHRONIZED block
    Thread A say:0
    Thread C enter the SYNCHRONIZED block
    Thread B say:1
    Thread A say:2
    Thread D enter the SYNCHRONIZED block
    Thread B say:3
    Thread C say:4
    
  • 共有1个答案

    刘翔宇
    2023-03-14

    问题1:

    在线程A和线程B进入SYNCHRONIZED块并调用wait()方法之后,为什么线程C和线程D进入而不是线程A说i,然后线程B说i?进入同步块的优先级是否高于刚刚调用wait()方法的线程?

    以下是Javadoc对等待/通知的描述:

    在当前线程放弃对此对象的锁定之前,唤醒的线程将无法继续。唤醒的线程将以通常的方式与可能主动竞争在此对象上同步的任何其他线程竞争;例如,唤醒的线程在成为锁定此对象的下一个线程时没有可靠的特权或劣势。

    这意味着,当线程 B 调用通知时,线程 A 将无法保证继续,并且线程 A 需要与在同步块开始时等待的线程 C 和 D 竞争。在您的情况下,实现只优先考虑线程 C 和 D。这就是您看到此输出的原因:

    Thread A enter the SYNCHRONIZED block --- 10:47:07.242
    Thread B enter the SYNCHRONIZED block --- 10:47:07.743
    Thread C enter the SYNCHRONIZED block --- 10:47:08.243
    Thread D enter the SYNCHRONIZED block --- 10:47:08.743
    

    问题2:

    为什么调用通知()方法只是唤醒调用等待()方法的最后一个线程?就像线程C和线程D一样,相互通知并相互等待,为什么没有任何其他等待线程?比如线程A和线程B。

    同样,Java规范并不保证优先级。恰好线程D对< code>notify的调用唤醒了线程C(它与线程A和B一起等待锁),线程C在打印“say”语句并Hibernate500ms后调用唤醒了线程D(它再次与线程A和B一起等待锁),直到它们退出while循环和同步块,从而先释放线程B的锁,然后释放线程A的锁

    我运行的示例输出:

    Thread A enter the SYNCHRONIZED block --- 09:35:59.836
    Thread D enter the SYNCHRONIZED block --- 09:36:00.336
    Thread C enter the SYNCHRONIZED block --- 09:36:00.836
    Thread B enter the SYNCHRONIZED block --- 09:36:01.336
    Thread C say:0 --- 09:36:01.836
    Thread B say:1 --- 09:36:02.337
    Thread C say:2 --- 09:36:02.837
    Thread B say:3 --- 09:36:03.337
    Thread C say:4 --- 09:36:03.837
    Thread B say:5 --- 09:36:04.337
    Thread C say:6 --- 09:36:04.837
    Thread B say:7 --- 09:36:05.337
    Thread C say:8 --- 09:36:05.837
    Thread B say:9 --- 09:36:05.837
    Thread D say:10 --- 09:36:05.837
    Thread A say:11 --- 09:36:05.838
    
     类似资料:
    • 我对通知方法的一点感到困惑。“notify() :它唤醒一个在同一对象上调用 wait() 的线程。因此,假设两个线程称为等待同一对象。那么当我调用通知时,将通知哪个线程?

    • 考虑有两个线程正在等待执行同步块。现在有机会在这种情况下等待,我真的需要调用notify()吗?我认为当同步块执行完成时,其他线程会释放锁吗?notify()方法的确切用途是什么? 线程专家请解释?

    • 1):单线程应用程序只会在用户的CPU上使用1个线程吗?提供更多的线程会使用多个CPU内核吗?如果声明的线程比用户的CPU多,会发生什么?

    • 教程这样说道:“内部调用了this.notifyAll()而不是this.notify(),使用notifyAll()将唤醒所有当前正在this锁等待的线程,而notify()只会唤醒其中一个(具体哪个依赖操作系统,有一定的随机性)。这是因为可能有多个线程正在getTask()方法内部的wait()中等待” 。 我有点疑惑的一句话是 “可能有多个线程正在getTask()方法内部的wait()中等

    • 我正在做一个项目,它使用原始Java并发结构,如等待()、通知()、通知()、Thread.run()、同步化等。在我的项目中,有多个线程(线程类的扩展)会定期从队列中获取一个对象。因此,我使用了一个有内部TimerWork类的Timer类。 我的问题是,我无法获得如何让其他线程定期唤醒。我的主要类不是这些线程或计时器类。因此,我从另一个类调用它们的运行。我不知道如何让这些线程每100毫秒等待和通

    • 如图所示, 位置 2 和位置3 为什么可以访问 位置1 (也就是主线程)的 point 局部变量 ? 毕竟 位置 2 和位置3 是另外两个线程啊 !! 当我加上 第10行代码后,thread1 和 thead2 中都不能访问主线程中的point 了。我知道这是内部类的“事实最终变量” 的限制。 如下图所示,就是我不理解的地方。(在 “栈内存” 层面) 我的猜测:之所以 thread1 和 trea