Stores a single object for the producer/consumer pattern and takes care of thread synchronization. : Lock Synchronize « Threads « Java






Stores a single object for the producer/consumer pattern and takes care of thread synchronization.

        
//package org.j4me.collections;

/**
 * Stores a single object for the producer/consumer pattern and takes care
 * of thread synchronization.  A first thread, the producer, can put an object
 * into the cubby hole using <code>set</code>.  If there already is an object
 * in the cubby hole then it is discarded.  Meanwhile a second thread, the
 * consumer, can get the object using <code>get</code>.  If no object is in
 * the cubby hole the consumer will block until one is available.
 * <p>
 * <code>CubbyHole</code> is valuable for several situations including where
 * a lot of information is produced and consumption is time consuming.  For
 * example an application that does expensive rendering based on location
 * events could only render based on the very latest location.   
 */
public class CubbyHole
{
  /**
   * The object stored by the producer.  If this is <code>null</code>
   * there is nothing to consume.
   */
  private Object cubby;

  /**
   * Called by the producer to put <code>data</code> into the cubby hole.
   * If there was another object stored in the cubby hole it will be
   * removed and returned.
   * <p>
   * This is a thread-safe method that returns immediately.  If another
   * thread, acting as the consumer, is blocking on <code>get</code> it
   * will start running so long as <code>data</code> is not <code>null</code>.
   *  
   * @param data is the information to store in the cubby hole.  If
   *  <code>null</code> then there is no job and any calls to <code>get</code>
   *  will block until <code>set</code> is called again with a non-
   *  <code>null</code> object.
   * @return The object in the cubby hole replaced by <code>data</code>
   *  or <code>null</code> if nothing was stored.
   */
  public synchronized Object set (Object data)
  {
    Object ret = cubby;
    cubby = data;

    // Unblock a consumer waiting on get().
    notifyAll();
    
    return ret;
  }

  /**
   * Called by the consumer to get an object stored in the cubby hole.
   * If nothing is stored this thread will block until <code>set</code>
   * is called by a different thread.
   * 
   * @return The object stored in the cubby hole by a call to <code>set</code>.
   *  This will never return <code>null</code>.
   * @throws InterruptedException if the program is exiting.
   */
  public synchronized Object get ()
    throws InterruptedException
  {
    // Block until a job is available.
    while ( cubby == null )
    {
      wait();  // Releases the lock on this when waiting and re-acquires when awaken
    }

    // Get the data in the cubby hole.
    Object ret = cubby;
    cubby = null;

    return ret;
  }

  /**
   * Looks at the cubby hole without removing the object from it.  This
   * is a non-blocking method.
   *  
   * @return The object in the cubby hole which will be <code>null</code>
   *  if nothing is being stored.
   */
  public synchronized Object peek ()
  {
    return cubby;
  }

  /**
   * Test is the cubby hole is empty.  This is a non-blocking method.
   * 
   * @return <code>true</code> if nothing is in the cubby hole or <code>
   *  false</code> if it has an object.
   */
  public synchronized boolean empty ()
  {
    return (cubby == null);
  }
}
---------------
package org.j4me.collections;

import org.j4me.*;
import j2meunit.framework.*;

/**
 * Tests the <code>CubbyHole</code> class.  It is a thread synchronization
 * helper that stores exactly one object.  A worker thread can get the very
 * latest information stored by a producer.
 * 
 * @see org.j4me.collections.CubbyHole
 */
public class CubbyHoleTest
  extends J4METestCase
{
  public CubbyHoleTest ()
  {
    super();
  }
  
  public CubbyHoleTest (String name, TestMethod method)
  {
    super( name, method );
  }
  
  public Test suite ()
  {
    TestSuite suite = new TestSuite();
    
    suite.addTest(new CubbyHoleTest("testBasics", new TestMethod() 
        { public void run(TestCase tc) {((CubbyHoleTest) tc).testBasics(); } }));
    suite.addTest(new CubbyHoleTest("testBlocking", new TestMethod() 
        { public void run(TestCase tc) {((CubbyHoleTest) tc).testBlocking(); } }));
    
    return suite;
  }
  
  /**
   * Tests that a cubby hole stores exactly one object.  Thread synchronization
   * is not covered by this test case.
   */
  public void testBasics ()
  {
    try
    {
      CubbyHole cubby = new CubbyHole();
      
      // Very there is nothing in the empty cubby hole.
      boolean isEmpty = cubby.empty();
      assertTrue("The cubby hole is empty.", isEmpty);
      
      Object peek = cubby.peek();
      assertNull("Nothing comes from peaking into an empty cubby hole.", peek);
      
      // Put something into the cubby hole.
      Integer i = new Integer( 13 );
      cubby.set( i );
      
      isEmpty = cubby.empty();
      assertFalse("The cubby hole has something in it.", isEmpty);
      
      peek = cubby.peek();
      assertSame("The cubby hole correctly stored our object.", i, peek);
  
      Object get = cubby.get();
      assertSame("Got the object stored in the cubby.", i, get);
  
      // The cubby hole should once again be empty.
      isEmpty = cubby.empty();
      assertTrue("The cubby hole is empty again.", isEmpty);
      
      peek = cubby.peek();
      assertNull("Nothing comes from peaking into the empty again cubby hole.", peek);
  
      // Put several objects into the cubby hole before taking one out.
      Integer i1 = new Integer( 1 );
      Integer i2 = new Integer( 2 );
      Integer i3 = new Integer( 3 );
      
      get = cubby.set( i1 );
      assertNull("Nothing returned from empty cubby hole.", get);
  
      get = cubby.set( i2 );
      assertSame("Old data i1 returned from cubby hole.", i1, get);
  
      get = cubby.set( i3 );
      assertSame("Old data i2 returned from cubby hole.", i2, get);
  
      get = cubby.get();
      assertSame("Newest data is in cubby hole.", i3, get);
    }
    catch (InterruptedException e)
    {
      fail( e.toString() );
    }
  }
  
  /**
   * Tests that a consumer thread blocks waiting for a producer to add
   * something to the cubby hole.
   */
  public void testBlocking ()
  {
    final CubbyHole one = new CubbyHole();
    final CubbyHole two = new CubbyHole();
    
    class Consumer extends Thread
    {
      public void run ()
      {
        try
        {
          // Block waiting for something in the first cubby hole.
          Object consume = one.get();
          
          // The producer thread should be blocking waiting for
          // this thread to put something into the second cubby hole.
          two.set( consume );
        }
        catch (Throwable t)
        {
          fail( t.toString() );
        }
      }
    }
    
    try
    {
      // Create a consumer thread.
      Consumer consumer = new Consumer();
      consumer.start();
      
      // Give up the CPU to let the consumer start and block.
      Thread.sleep( 0 );

      // Put some data into the first cubby hole to unblock the consumer.
      Integer data = new Integer( 13 );
      one.set( data );
      
      // Get data from the second cubby hole.  This thread will block
      // until the consumer puts something into it.
      Integer result = (Integer)two.get();
      
      // Verify the consumer thread read our original data from the
      // first cubby hole and put it into the second.
      assertSame("Data integrety verified.", data, result);
    }
    catch (InterruptedException e)
    {
      fail( e.toString() );
    }
  }
}

   
    
    
    
    
    
    
    
  








Related examples in the same category

1.Thread: Dining Philosophers
2.Synchronizing on another objectSynchronizing on another object
3.Operations that may seem safe are not, when threads are presentOperations that may seem safe are not, when threads are present
4.Synchronizing blocks instead of entire methodsSynchronizing blocks instead of entire methods
5.Boolean lockBoolean lock
6.Static synchronized blockStatic synchronized block
7.Thread notifyThread notify
8.Thread deadlockThread deadlock
9.Synchronize methodSynchronize method
10.Threads joinThreads join
11.Static synchronizeStatic synchronize
12.No synchronizeNo synchronize
13.Thread synchronizationThread synchronization
14.Synchronized Block demoSynchronized Block demo
15.Interruptible Synchronized Block Interruptible Synchronized Block
16.SignalingSignaling
17.Simple Object FIFOSimple Object FIFO
18.Object FIFOObject FIFO
19.Byte FIFOByte FIFO
20.Daemon Lock
21.Determining If the Current Thread Is Holding a Synchronized Lock
22.Handle concurrent read/write: use synchronized to lock the data
23.Lock for read and write
24.Read Write Lock
25.Coordinates threads for multi-threaded operations
26.A reader-writer lock from "Java Threads" by Scott Oak and Henry Wong.
27.Invoke a series of runnables as closely to synchronously as possible
28.This program shows how multiple threads can safely access a data structure, using synchronized methods
29.This program shows data corruption when multiple threads access a data structure.
30.The BooleanLock class provides a useful encapsulation of a boolean variable that is easily and safely accessed from multiple theads.