| Concurrent processes, i.e. threads, are extremely useful tools 
              but, as we see in the discussions of synchronization in Chapter 
              8: Java, can be tricky to handle when the processes must interact 
              with each other. Java 5.0 came with many additional tools for the 
              programmer to use when threading.  The Concurrency 
              Utilities - Java Language Programming Guide gives an overview 
              of the new tools. This article - Getting 
              to Know Synchonizers - Java Tech Tips - Feb.26.2005 - gives 
              a nice introduction to the follwoing four synchronization tools: Semaphores: The wait-notify system in standard Java is not the only way that 
              thread synchronization can be done. A classic approach in other 
              languages is the semaphore, 
              which is a protected variable allows up to a given N 
              number of threads to access a resource simultaneously. As described 
              in the tutorial, 
              an instance of the new Java Semphore class 
              can be used to limit how many many treads can invoke a particular 
              method at any one time.
 Barriers: Say that you are simulating a system of many mutally interacting 
              particles, each of whose motion depends on the position of the other 
              particles. You assign a thead to each particle to calculate its 
              velocity, position, etc. for an increment in time based on the sum 
              of the forces from the other particles. You clearly have to constrain 
              each thread to calculate only one step and then wait for all the 
              other particle to "catch up". Otherwise, some threads 
              will get far ahead of the others and calculate their particle motions 
              incorrectly based on previous positions of the other particles rather 
              than on where those other particles would actually be at the same 
              time step.
 So a given thread should do its calculation and then wait until 
              all the other threads are finished before starting to calculate 
              the next step. This could be done with a barrier synchronization 
              technique. This term implies that a thread is stopped at the barrier 
              until all threads reach it. Once all have reached it, the barrier 
              is lowered and they all start a new round of step calculations and 
              all again wait at the barrier after they finish their work.  The concurrency utilities offers the CyclicBarrier 
              class to provide this tool. (It's called cyclic because it can be 
              reused after each time the waiting threads are released by it.) 
              The class includes the option of running a thread when once all 
              the threads reach the barrier. The tutorial 
              uses the case of adding up the rows of matrix. Latches: The CountDownLatch class allows one 
              to prevent a set of threads from running until you are ready for 
              them to. For example, you might want to create the threads and then 
              do some initialization tasks before starting them all simultaneously. 
              The tutorial 
              shows how to use the CountDownLatch to 
              start several threads simultaneously and also to stop them all at 
              the same time.
 The join() method in the Thread 
              class can also be used to allow for two or more threads to finish 
              togehter. However, latches can be used to create several places 
              where threads must wait before proceeding with further processing. 
             Exchangers: Say that you want to create a producer/consumer 
              system in which the producer fills up a buffer, passes the filled 
              buffer to the consumer, which then begins to empty that buffer for 
              its own purposes. Meanwhile, the producer could be filling a new 
              buffer. Rather than creating a new buffer object each time, the 
              consumer could pass the producer an old buffer that it had finished 
              emptying.
 The java.util.concurrent.Exchanger 
              class provides for this exchange of objects. The tutorial 
              provides a producer/consumer example that illustrates this.  More new concurrency Tools: In Chapter 
              10: Java: The Concurrency Utilities, we discuss the new Executor 
              framework, which relieves the programmer of threading toil such 
              as creating thread pools, killing a thread safely, etc. The Callable 
              interface improves on Runnable by allowing 
              for the return of data and for throwing and catching an exception 
              from a thread.
   References & Web Resources   Most recent update: Oct. 6, 2005   |