Concurrency in Java

The Java language has supported concurrency from the very start. However, the concurrency constructs have undergone modification; in particular, several dangerous constructs have been deprecated (dropped from the language). The latest version (1.5) has an extensive library of concurrency constructs java.util.concurrent, designed by a team led by Doug Lea. For more information on this library see the Java documentation and [44]. Lea’s book explains how to integrate concurrency within the framework of object-oriented design and programming a topic not covered in this book.

The Java language supports concurrency through objects of type Thread. You can write your own classes that extend this type as shown in Listing 2.4. Within a class that extends Thread, you have to define a method called run that contains the code to be run by this process. Once the class has been defined, you can define fields of this type and assign to them objects created by allocators (lines 11-12). However, allocation and construction of a Thread object do not cause the thread to run. You must explicitly call the start method on the object (lines 13-14), which in turn will call the run method.

The global variable n is declared to be static so that we will have one copy that is shared by all of the objects declared to be of this class. The main method of the class is used to allocate and initiate the two processes; we then use the join method to wait for termination of the processes so that we can print out the value of n. Invocations of most thread methods require that you catch (or throw) InterruptedException .

If you run this program, you will almost certainly get the answer 20, because it is highly unlikely that there will be a context switch from one task to another during the loop. You can artificially introduce context switches between between the two assignment statements of the loop: static method Thread.yield() causes the currently executing thread to temporarily cease execution, thus allowing other threads to execute.

Since Java does not have multiple inheritance, it is usually not a good idea to extend the class Thread as this will prevent extending any other class. Instead, any class can contain a thread by implementing the interface Runnable:

class Count implements Runnable {
  @override
  public void run() { ... }
}

Threads are created from Runnable objects as follows:

Count count = new Count();
Thread t1 = new Thread(count);

or simply:

Thread tl = new Thread(new Count());

Volatile

A variable can be declared as volatile (Section 2.9):

volatile int n = 0;

Variables of primitive types except long and double are atomic, and long and double are also atomic if they are declared to be volatile. A reference variable is atomic, but that does not mean that the object pointed to is atomic. Similarly, if a reference variable is declared as volatile it does not follow that the object pointed to is volatile. Arrays can be declared as volatile, but not components of an array.