【问题标题】:Wake waiting threads in javajava唤醒等待线程
【发布时间】:2016-09-24 03:38:06
【问题描述】:

我有 4 个线程同时填充 50000000x4 矩阵。为了确保写入的安全性,我使用了 AtomicInteger 作为指针。每次迭代每个线程将指针值复制到 threadPointer 并使用它来填充 . 获得指针 == buffer.length 的第一个线程启动例程将缓冲区刷新到内存中。此时其他线程应等待线程完成其工作。 这是我的代码:

if ((threadPointer = pointer.getAndAdd(1)) >= buffer.length ){
    synchronized (flag){
        if(threadPointer == buffer.length){
            sampledSelection();
            pointer.set(0);
            threadPointer = pointer.getAndAdd(1);
            flag.notifyAll();
        }else{
            System.out.println("waiting");
            flag.wait();
            threadPointer = pointer.getAndAdd(1);
            System.out.println("Awaken!");
        }
    }
}

我的问题是notifyAll() 没有唤醒等待的线程。我该如何解决这个问题?

【问题讨论】:

  • 您没有在您的wait 呼叫中使用guarded blocks。这允许竞争条件,即如果一个线程将到达 wait 调用但还没有,而另一个线程调用 notifyAll 太快,导致它永远等待。
  • 我明白了。我发现我的代码有一个导致意外行为的错误。其中之一导致线程调用 notifyAll() 在我预期会导致您写的内容之前。谢谢。

标签: java multithreading wait


【解决方案1】:

听起来你想通了,但为了后代......

我的问题是 notifyAll 不会唤醒等待的线程。我该如何解决这个问题?

是的,这里有一个经典的比赛条件。假设大约同时有 3 个线程来执行pointer.getAndAdd(1)

  1. 线程#1 首先调用synchronized (flag) 并进入保护区。
  2. 线程#2 和#3 调用synchronized (flag),但在线程#1 解锁之前它们被锁定。
  3. 线程#1 的pointer 值等于缓冲区长度,因此它调用sampledSelection();,将pointer 重置为0,调用notifyAll(),然后解锁。
  4. 线程#2(假设)现在进入synchronized 部分。它的 pointer 值不相等,所以它转到 wait() 解锁。
  5. 线程#3 现在进入synchronized 部分。它的 pointer 值不相等,所以它转到 wait() 解锁。

如果没有人回来打电话给notifyAll(),那么他们将永远等待。

正如您所知道的,重要的是要意识到notifyAll() 方法唯一起作用的时间是线程已经在等待。通常应该发生的是线程应该查看条件字段以查看它们是否应该等待。

要注意的另一件事是确保synchronized 所在的对象是一个常量。在您的情况下,flag 应定义为:

private final Object flag = new Object();

如果您的flag 可以分配给另一个值,那么线程将不会锁定(或发出信号)同一对象,这会导致问题。始终确保锁定 final 对象。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2020-08-31
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 2021-08-09
    • 2010-10-29
    • 2014-07-29
    • 1970-01-01
    • 2013-02-03
    相关资源
    最近更新 更多