3
votes

Essentially what I want is a BlockingQueue of size=1. I have a "listener" thread that simply waits, blocking until an object is put into the queue, and then retrieves it--and a "producer" thread that actually puts the object into the queue.

I can implement this with some synchronized blocks and a BlockingQueue implementation, but that seems like overkill. Is there a better, simpler way to do what I want?

Example interface:

public interface Wait<T> {
  /**
   * If "put" has never been called on this object, then this method will
   * block and wait until it has. Once "put" has been called with some T, this
   * method will return that T immediately.
   */
  public T get() throws InterruptedException;

  /**
   * @param object The object to return to callers of get(). If called more
   * than once, will throw an {@link IllegalStateException}.
   */
  public void put(T object);
}
2
Well, that's exactly what the bounded new ArrayBlockingQueue(1) is for (use the 'add' method, not 'put'). The object is pretty lightweight in terms of synchronization and the memory overhead shouldn't hurt unless you have tens of thousands of them. Do you have any special concerns? - ddimitrov

2 Answers

3
votes

You mean something like SynchronousQueue? Another useful class is Exchanger

2
votes

I found code for a class called "ObjectLatch" here: http://forums.sun.com/thread.jspa?threadID=5321141

package jfco.progs;

import java.util.concurrent.CountDownLatch;

/**
 * <H1>A Blocking Object Latch</H1> This class implements a blocking object
 * latch, that acts as a synchronizer between a producer of an object and it's
 * consumer(s).
 * <p>
 * An object is set with <code>set()</code>only ONCE. Further attempts to set
 * the object are just ignored.<br>
 * <p>
 * Consumers request the object with <code>get()</code>. If the object is not
 * already set, consumers are blocked waiting until the object is available or <br>
 * until an interrupt (InteruptedException) terminates the wait.
 * <p>
 * The latch can be tested for object availability with isAvailable(), which
 * answers true if the object has already been set. <br>
 */
public class ObjectLatch<R> {

    /** The object. */
    private R object = null;

    /** The latch counter created and set to 1. */
    private final CountDownLatch latch = new CountDownLatch(1);

    /**
     * Checks if the object is already available (has been already set).
     * 
     * @return true, if the object is already available (has been already set)
     */
    public boolean isAvailable() {
        return latch.getCount() == 0;
    }

    /**
     * Sets the object if it is not already set. Otherwise ignore this request.
     * 
     * @param object
     *            the object
     */
    public synchronized void set(R object) {
        if (!isAvailable()) {
            this.object = object;
            latch.countDown();
        }
    }

    /**
     * Get the object if it is already available (has already been set).
     * <p>
     * If it is not available, wait until it is or until an interrupt
     * (InterruptedException) terminates the wait.
     * 
     * @return the object if it is already available (has already been set)
     * 
     * @throws InterruptedException
     */
    public R get() throws InterruptedException {
        latch.await();
        synchronized (this) {
            return object;
        }
    }
}