在java中唤醒等待线程

时间:2016-09-24 03:38:07

标签: java multithreading wait

我有4个线程同时填充50000000x4矩阵。为了确保写入的安全性,我使用了AtomicInteger作为指针。每次迭代每个线程将指针值复制到threadPointer并用它来填充a。 获取指针== 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()没有唤醒等待的线程。我该如何解决这个问题?

1 个答案:

答案 0 :(得分: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()
  6. 如果没有人回来致电notifyAll(),那么他们将永远等待。

    正如您已经想到的那样,重要的是要意识到notifyAll()方法唯一有效的方法是线程已经在等待。通常情况下,线程应该查看条件字段以查看它们是否应该等待。

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

    private final Object flag = new Object();
    

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

    希望这有帮助。