Aalto Aalto - 9 months ago 40
Java Question

Wake waiting threads in java

I have 4 threads that are filling concurrently an 50000000x4 matrix. To ensure writes' safety I used an AtomicInteger as pointer. Each iteration each thread copy the pointer value into threadPointer and use it to fill a .
The first thread that get pointer == buffer.length starts a routine to flush the buffer into memory. The other threads at this point should wait for the the threads to finish its job.
This is my code:

if ((threadPointer = pointer.getAndAdd(1)) >= buffer.length ){
synchronized (flag){
if(threadPointer == buffer.length){
threadPointer = pointer.getAndAdd(1);
threadPointer = pointer.getAndAdd(1);

My problem is that
doesn't wake the waiting threads.How can I fix this?

Answer Source

It sounds like you figured it out but for posterity...

My problem is that notifyAll doesn't wake the waiting threads. How can I fix this?

Right, you have a classic race condition here. Let's say 3 threads come and do the pointer.getAndAdd(1) around the same time.

  1. Thread #1 calls synchronized (flag) first and gets into the protected area.
  2. Threads #2 and #3 call synchronized (flag) but they are locked out until thread #1 unlocks.
  3. Thread #1's pointer value is equal to the buffer length so it calls sampledSelection();, resets the pointer to 0, calls notifyAll(), and then unlocks.
  4. Thread #2 (let's say) now enters the synchronized section. It's pointer value is not equal so it goes to wait() which unlocks.
  5. Thread #3 now enters the synchronized section. It's pointer value is not equal so it goes to wait() which unlocks.

If no one comes back to call notifyAll() then they will wait forever.

As you've figured out, it is important to realize that the only time the notifyAll() method works is if the threads are already waiting. Typically what should happen is that the threads should look at condition field to see if they should wait.

Another thing to watch out for is to make sure that the object that you are synchronized on is a constant. In your case flag should be defined like:

private final Object flag = new Object();

If your flag can be assigned to another value then the threads will not be locking (or signalizing) on the same object which would cause problems. Always make sure that you lock on a final object.

Hope this helps.