【问题标题】:How to notifyAll threads in a class in JAVA?如何在 JAVA 中通知类中的所有线程?
【发布时间】:2020-05-01 04:28:48
【问题描述】:

我可以创建一个静态函数来通知在此类的任何实例中等待的所有线程吗?

(这里的逻辑是我有队列中有线程在等待,因为它们是空的,我想在调用这个函数时完成程序的运行)

queue = new Vector<T>();

 public synchronized T extract(){
        while(queue.isEmpty())
            try {
                this.wait();
                if(!active) {return null;}
            }catch(InterruptedException e) {}
        T t = queue.elementAt(0);
        queue.remove(0);
        return t;
}

这是提取方法。 当队列为空时,线程进入等待状态。 我想让布尔值“激活”为 false 并 notifyAll。

那我会确保线程不会再调用这个方法

【问题讨论】:

  • 你能添加你的代码sn-p吗?你面临什么问题?
  • 我添加了部分代码和一些额外的解释。
  • 不,除非你列出所有类的实例。
  • (不相关,但我已经看到您的代码存在问题(除了最少使用大括号):如果在进入 synchronized 块之前它不是 active ,您可以提交wait。此外,通常评论(可变)全局状态是一个坏主意。)
  • 忽略中断的线程是无法终止的流氓线程。不要忽略 InterruptedExceptions。您可以做的最好的事情是使用throws InterruptedException 声明您的方法并完全删除try/catch;或者将整个方法体放在 try 块中,这样中断就会干净地终止它。永远不要写一个空的 catch 块;至少,在其中调用e.printStackTrace();。毕竟,您想知道您的方法行为异常的原因。

标签: java multithreading static queue wait


【解决方案1】:

这里的逻辑是我的队列中有线程在等待,因为它们是空的,我想在调用这个函数时完成程序的运行

IMO,对您的问题更好的解决方案是继续使用每个实例的锁,但在需要关闭所有队列时向每个队列提交一个毒丸

final T poison_pill = new T(...);

public synchronized T extract(){
    while(queue.isEmpty())
        try {
            this.wait();
        }catch(InterruptedException e) {}
    T t = queue.elementAt(0);
    if (t == poison_pill) {
        ...My preference would be to raise an exception here, but...
        return NULL;              // ...this was in your original example.
    }
    else {
        queue.remove(0);
        return t;
    }
}

如果您真的希望能够同时notify() 所有不同的实例,那么您必须将它们全部设置为wait() 在同一个全局锁定对象上.

final Object global_lock = new Object();

public T extract(){
    synchronized(global_lock) {
        while(queue.isEmpty())
            try {
                global_lock.wait();
                if(!active) {return null;}
            }catch(InterruptedException e) {}
        T t = queue.elementAt(0);
        queue.remove(0);
        return t;
    }
}

然后在其他地方:

synchronized(lock) {
    ...
    global_lock.notifyAll();
}

【讨论】:

  • 我也更喜欢毒丸这个主意。所以你是说,此刻我想终止我的队列,我应该从外部来源(实际上正在关闭事物的那个人)插入一些假元素(毒丸) - 这将通知线程,当我尝试提取它,如果它是我终止队列和线程的药丸?
  • @DanBoguslavsky 这两个想法都很棒。不过,我更喜欢 global_lock 机制。
  • @SreeKumar,这是一个权衡。 global_lock 不太复杂,但它会降低程序的性能,因为每次将对象添加到任何一个队列时,每个消费者线程都必须唤醒。有时,简单的解决方案就是您想要的解决方案。有时,为了获得高性能的解决方案而付出额外的工作是值得的。
猜你喜欢
  • 2017-09-03
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 2011-02-27
  • 1970-01-01
  • 1970-01-01
  • 2020-04-16
  • 1970-01-01
相关资源
最近更新 更多