java - 调用notify并不会唤醒其他等待线程

标签 java multithreading

我有两个线程,T1 和 T2。两者都有自己的数组列表,我想从 T1 中删除数组列表的一个元素,删除后,我希望它想要直到 T2 数组列表元素也删除

所以流程应该是这样的:

t1 remove element
t2 remove element

t1 remove element
t2 remove element
.
.
.

这是我的代码:

import static java.lang.Thread.sleep;
import java.util.ArrayList;

public class ThreadsTest {

    public static void main(String[] args) {
        Thread t1 = new Thread(new T1());
        t1.start();

        Thread t2 = new Thread(new T2());
        t2.start();
    }
}

class T1 implements Runnable {

    private ArrayList<String> list;

    public T1() {
        list = new ArrayList();
        list.add("t1 1");
        list.add("t1 2");
        list.add("t1 3");
        list.add("t1 4");
        list.add("t1 5");
    }

    @Override
    public void run() {
        while (!list.isEmpty()) {
            System.out.println(list.remove(0));
            try {
                synchronized (this) {
                    wait();
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

}

class T2 implements Runnable {

    private ArrayList<String> list;

    public T2() {
        list = new ArrayList();
        list.add("t2 1");
        list.add("t2 2");
        list.add("t2 3");
        list.add("t2 4");
        list.add("t2 5");
    }

    @Override
    public void run() {
        while (!list.isEmpty()) {
            System.out.println(list.remove(0));
            try {

                synchronized (this) {
                    notifyAll();
                    sleep(1000);
                }

            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

}

为什么调用notify并不能唤醒T1?以及如何修复它?

最佳答案

您的代码中有 2 个问题:

首先,您正在同步/等待监视器“this”,这是实际的对象,因此对于 T1,它是 T1,对于 T2,它是 T2。为了正确地做到这一点,两个线程需要在同一个对象上同步/等待。执行此操作的常见方法是专门创建这样的对象:

final static Object monitor = new Object();

请注意,final 关键字在这里很重要,您不想在中间意外更改监视器。

但即使您这样做,也不能保证在 T2 调用 notifyAll() 期间 T1 已经在等待,因为线程的执行顺序未定义。实际上,这可能会导致 T1 在删除后的最后一个等待调用期间死锁,因为 T2 已经完成。

编辑:如何使用 Phaser 执行此操作

声明两个线程都可以使用的 Phaser 实例:

static final Phaser phaser = new Phaser(2); // 2 threads = 2 parties

T1的run方法变为:

while (!list.isEmpty()) {
  System.out.println(list.remove(0));
  phaser.arriveAndAwaitAdvance();
  phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();

T2的run方法变为:

while (!list.isEmpty()) {
  phaser.arriveAndAwaitAdvance();
  System.out.println(list.remove(0));
  phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();

在这种情况下,取消注册不是必需的,而是作为一种安全机制:一旦取消注册,系统就可以继续,而无需刚刚完成的线程。

关于java - 调用notify并不会唤醒其他等待线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20440485/

相关文章:

java - Java中验证一个点是否是二次贝塞尔曲线的一部分

c++ - POSIX:如何暂停线程?

java - 将 FutureTask 转换为 ScheduledFuture

java - 使用 valueOf 枚举的字符串与 java.lang.IllegalArgumentException 崩溃

java - JPL 库在多线程程序中的意外行为(Java 和 Prolog 的接口(interface))

java - 初学者 Android : ListView to affect the next class

java - 如何在 Spring Boot 项目 : 上正确配置 Intellij IDEA 中的 jRebel

c# - 使用联锁用法

c - 为什么 CILK_NWORKERS 会影响只有一个 cilk_spawn 的程序?

python - threading.timer 只打印 for 循环的最后一个值