2016-09-24 98 views
0

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

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()不会唤醒等待我threads.How可以解决这一问题?

+2

您的'wait'调用没有使用[guarded blocks](https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)。这允许竞争条件,即如果一个线程将要到达'wait'调用但还没有,另一个线程过早地调用'notifyAll',导致它永远等待。 –

+0

我明白了。我发现我的代码有一个导致意外行为的错误。其中之一导致线程调用notifyAll(),然后我期望导致你写的内容。谢谢。 – Aalto

回答

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(比方说)现在进入​​部分。这是pointer值不相等,所以它解锁wait()
  5. 线程#3现在进入​​部分。这是pointer值不相等,所以它解锁wait()

如果没有人回来呼叫notifyAll()那么他们将永远等待。

正如你所想的那样,重要的是要认识到notifyAll()方法的唯一工作方式是如果线程已经在等待。通常应该发生的是线程应该查看条件字段以查看是否应该等待。

另一件需要注意的事情是要确保你的对象​​是一个常数。你的情况应该flag等来定义:

private final Object flag = new Object(); 

如果您flag可以被分配到另一个值,那么线程将不是同一个对象,这将导致问题上锁定(或信号化)。务必确保您锁定了一个final对象。

希望这会有所帮助。