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.