Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Programming Java threads in the real world, Part 9

More threads in an object-oriented world: Synchronous dispatchers, active objects, detangling console I/O

  • Print
  • Feedback

Page 3 of 6

I've solved the problem of implementing a synchronous dispatcher with the Synchronous_dispatcher class in Listing 1. You can use the dispatcher in two ways. First of all, tasks can be added independently and then executed. The following code prints the string "hello world" three times.

    Synchronous_dispatcher dispatcher = new Synchronous_dispatcher();
    dispatcher.add_handler( new Runnable()
                           {   public void run(){ System.out.print("hello "); }
                            }
                          );
    dispatcher.add_handler( new Runnable()
                           {   public void run(){ System.out.print("world\n"); }
                            } 
                          );
    dispatcher.dispatch( 3 );


You can add a time delay between each chunk as follows:

    dispatcher.metered_dispatch( 2, 1000 ); // one second delay between chunks


This call prints the following:

hello <pause> world <pause> hello <pause> world


A second version of add_handler() is provided to add an entire array of Runnable chunks to the dispatcher. The elements of the array are distributed as evenly as possible among the previously added chunks. For example, the following code prints "Hello (Bonjour) world (monde)":

    Runnable[] first_task =
    {   new Runnable(){ public void run(){ System.out.print("Hello"); }},
        new Runnable(){ public void run(){ System.out.print(" world");}}
    };
    Runnable[] second_task =
    {   new Runnable(){ public void run(){ System.out.print(" (Bonjour)");}},
        new Runnable(){ public void run(){ System.out.print(" (monde)"  );}}
    };
    dispatcher = new Synchronous_dispatcher();
    dispatcher.add_handler( first_task  );
    dispatcher.add_handler( second_task );
    dispatcher.dispatch( 1 );


The chunks of a task can share data, if necessary, through the instance variables of the class that contains the array definitions.

Of course, several dispatchers can each run on their own threads, in which case you have a situation much like Sun's "green thread" model, where cooperative and preemptive threads both share the same process.

Looking at the implementation, the individual Runnable chunks are kept in the events LinkedList (Listing 1, line 9). The one-element version of add_handler(Runnable) (Listing 1, line 12) just tacks the new element onto the end of the list. The array version add_handler(Runnable[]) (Listing 1, line 17) is trickier to implement than you might expect. This is because the incoming array could be larger than the existing list (in which case you want the existing list elements dispersed evenly between array elements), or smaller than the existing list (in which case you want the incoming array elements to be dispersed evenly throughout the existing list). I've chosen to make matters easier by first converting the list to an array so that I can work with two similar data structures. I then rebuild the linked list, first copying one or more elements from the larger array into the list, then copying one element from the smaller array, then one or more elements from the larger array, and so forth. An earlier version of this method did the same thing without first doing the list-to-array conversion, but it was both considerably more complex and slower then the current version.

  • Print
  • Feedback

Resources