Newsletter sign-up

Sign up for our technology specific newsletters.

Enterprise Java
View all newsletters

Email Address:

Using threads in Java, Part 2

Create communication channels that operate between threads

In part one of this series of colums, I showed you how two or more threads in the Java runtime can synchronize with the wait() and notify() methods in class Object. In this installment we will write a class that uses these techniques to create a communication channel that operates between threads.

The communication channel performs four tasks. It

  • opens a connection to a named channel;
  • puts data into that channel;
  • pulls data out of the channel;
  • releases a channel when it is no longer needed.


This model is pretty typical of such designs.

The first of these, opening a named channel, requires that the class be able to share information (the channel registry) between threads. In Java, threads typically run in a shared address space. Subsequently, static fields in a Java class are shared across all instances of that class. You will recall that static instance variables (sometimes called class variables) do not require that an object instance be created to access them. Instead, they may be accessed using the Classname.variable_name syntax. For the purposes of our example, however, the more salient property is that they are visible to all threads.

Let the games begin

To create our DataChannel class we start out with this code:

 1    package util.comm;
 2
 3    import java.util.Hashtable;
 4    import java.util.Enumeration;
 5
 6    public class DataChannel {
 7
 8        private Hashtable TIDs;
 9
10        private DataChannel() {
11            TIDs = new Hashtable();
12        }
13
14        private static Hashtable registry = null;
15
16    /** getChannel (writer version) */
17        public static synchronized DataChannel getChannel(String name) {
18        if (registry == null)
19        registry = new Hashtable();
20        DataChannel it = (DataChannel) registry.get(name);
21        if (it == null) {
22            it = new DataChannel();
23            it.myName = name;
24            registry.put(name, it);
25        }
26        return it;
27        }


Line 1 puts this code in the util.comm package. There are two advantages to doing this: the classes for the data channels don't clutter up our main classes directory; and we can create a "helper" class named DataItem that is private to this package. Note that the package statement must be the first non-comment line in the file.

Lines 3 through 13 are the constructor for a new DataChannel object. As you can see, the constructor is declared private. This declaration makes it impossible for any object, except a DataChannel object, to construct a new instance of a DataChannel. This is a common technique to restrict the ability to construct new objects to a static method like the one in line 17.

Line 14 declares the registry hash table. Because this declaration is static and private, the hash table is shared across thread address spaces, but accessible only to the methods in DataChannel.

Finally, in lines 17 through 27, comes the channel-writer version of the getChannel() method. As a static method, it is accessed using the syntax:

DataChannel dc = DataChannel.getChannel("name");


Because it is a method in DataChannel, it is allowed to manipulate the private registry hash table and to call the private constructor defined in the class. Static methods such as this one that return an object of their own class type are called factory methods. This term is used because unlike constructors that simply allocate an object from the heap, factory methods manufacture one.

Resources