11

I have a Java Thread which exposes a property which other threads want to access:

class MyThread extends Thread {
   private Foo foo;
   ...
   Foo getFoo() {
     return foo;
   }
   ...
   public void run() { 
     ...
     foo = makeTheFoo();
     ...
   }
}

The problem is that it takes some short time from the time this runs until foo is available. Callers may call getFoo() before this and get a null. I'd rather they simply block, wait, and get the value once initialization has occurred. (foo is never changed afterwards.) It will be a matter of milliseconds until it's ready, so I'm comfortable with this approach.

Now, I can make this happen with wait() and notifyAll() and there's a 95% chance I'll do it right. But I'm wondering how you all would do it; is there a primitive in java.util.concurrent that would do this, that I've missed?

Or, how would you structure it? Yes, make foo volatile. Yes, synchronize on an internal lock Object and put the check in a while loop until it's not null. Am I missing anything?

Mohsen Nosratinia
  • 9,844
  • 1
  • 27
  • 52
Sean Owen
  • 66,182
  • 23
  • 141
  • 173

9 Answers9

16

If foo is initialized only one time, a CountDownLatch is a great fit.

class MyThread extends Thread {

  private final CountDownLatch latch = new CountDownLatch(1);

  ...

  Foo getFoo() throws InterruptedException
  {
    latch.await(); /* Or use overload with timeout parameter. */
    return foo;
  }

  @Override
  public void run() {
    foo = makeTheFoo()
    latch.countDown();
  }

}

Latches provide the same visibility behavior as the volatile keyword, meaning that reading threads will see the value of foo assigned by the thread, even though foo isn't declared volatile.

erickson
  • 265,237
  • 58
  • 395
  • 493
3

In general notify() and notifyAll() are the methods you want. notify() is dangerous if only one item is creating the Foo and many threads might wait for it. But I think there are some other issues here.

I wouldn't make the Thread the place to store the Foo. Doing so means you have to keep a thread around after Foo is created. Why not make another object to store the Foo, and have the creating thread write to it?

Then I would have getFoo() test foo and only wait if it was non-null (don't forget to synchronize it with itself and with the foo setter).

DJClayworth
  • 26,349
  • 9
  • 53
  • 79
  • Agree, I wish it weren't so. In this case I really have to make the object within run(). It's a GUI app with weird needs. – Sean Owen May 14 '10 at 20:29
1

Try the CountDownLatch:

class MyThread extends Thread {
   private volatile CountDownLatch latch;
   private Foo foo;
   MyThread(){
      latch = new CountDownLatch(1);
   }
   ...
   Foo getFoo() {
     latch.await(); // waits until foo is ready
     return foo;
   }
   ...
   public void run() { 
     ...
     foo = makeTheFoo();
     latch.countDown();// signals that foo is ready
     ...
   }
}

I don't think wait/notifyAll will work, because every wait will expect a notify. You want to notify once and then never bother with notification again, then any other thread that's calling getFoo will either block until foo is initialized or just get foo if it's already initialized.

Kiril
  • 39,672
  • 31
  • 167
  • 226
  • Actually, there's a subtle bug here: since `latch` isn't `final` or `volatile`, it's not guaranteed to be "visible" to other threads. Might not be an issue in practice, but the guarantee doesn't really cost anything. – erickson May 14 '10 at 20:23
1

I'd use any of the BlockingQueue's in java.util.concurrent More specifically, if there is one thread waiting for Foo and one producing it I'd use a SynchronousQueue in cases of more producers and/or more consumers my default option is a LinkedBlockingQueue, but other implementations might be better suited to your application. Your code then becomes:

class MyThread extends Thread {
   private SynchronousQueue<Foo> queue = new SynchronousQueue<Foo>();
   ...
   Foo getFoo() {
     Foo foo;
     try {
        foo = queue.take();
     }
     catch (InteruptedException ex) {
        ...stuff ...
     }
     return foo;
   }
   ...
   public void run() { 
     ...
     foo = makeTheFoo();
     try {
        queue.put(foo);
     }
     catch (InteruptedException ex) {
        ...stuff ...
     }
     ...
   }
}
jilles de wit
  • 7,060
  • 3
  • 26
  • 50
  • 1
    SynchronousQueue is a handy construct in many cases, but it doesn't fit the requirement here very well: `foo` is only initialized once, and read possibly many times. This would only allow `foo` to be read once. Other attempts to read the property would block forever. – erickson May 14 '10 at 20:18
  • Yes, you are correct, I had missed the "only initialized once" part. I thought this was more of a producer/consumer situation. – jilles de wit May 16 '10 at 12:14
0

You can use the the wait() and notify() methods:

Simple example here:

http://www.java-samples.com/showtutorial.php?tutorialid=306

Robben_Ford_Fan_boy
  • 8,494
  • 11
  • 64
  • 85
  • Definitely, I can roll a solution by hand. I think it's a tad more complex than this -- the field should be `volatile` and we need `notifyAll()` to start -- so I was hoping for comments on what else I need, or a pre-packaged solution that's definitely right. – Sean Owen May 14 '10 at 19:57
  • @Sean In that case I would go with DJClayworth's suggestion – Robben_Ford_Fan_boy May 14 '10 at 20:08
0

As I understand, concurrent stuff is created explicitly not to wait and do what you want right away — but if it is possible at all. In your case you need to wait until something is available, so your only option is, uh, to wait(). In short, it seems that the way you described it is the only correct way.

0

If initialization is a one shot deal, try java.util.concurrent.CountDownLatch.

fgantt
  • 31
  • 5
0

Is lazy initialization an option?

synchronized Foo getFoo() {
    if (foo == null)
        foo = makeFoo();
    }
    return foo;
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
meriton
  • 68,356
  • 14
  • 108
  • 175
0

Maybe try my fancy FutureValue class...

import java.util.concurrent.CountDownLatch;

public class FutureValue<T> {
private CountDownLatch latch = new CountDownLatch(1);
private T value;

public void set(T value) throws InterruptedException, IllegalStateException {
    if (latch.getCount() == 0) {
        throw new IllegalStateException("Value has been already set.");
    }
    latch.countDown();
    this.value = value;
}

/**
 * Returns the value stored in this container. Waits if value is not available.
 * 
 * @return
 * @throws InterruptedException
 */
public T get() throws InterruptedException {
    latch.await();
    return value;
}

}

// Usage example
class MyExampleClass {
@SuppressWarnings("unused")
private static void usageExample() throws InterruptedException {
    FutureValue<String> futureValue = new FutureValue<>();

    // the thread that will produce the value somewhere
    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                futureValue.set("this is future");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).run();

    String valueProducedSomewhereElse = futureValue.get();
}
}
ed22
  • 1,127
  • 2
  • 14
  • 30