Concurrency and Multithreading - Wrox Press Java Programming 24-Hour Trainer 2nd (2015)

Wrox Press Java Programming 24-Hour Trainer 2nd (2015)

Lesson 17. Concurrency and Multithreading

Developing Java applications that implement concurrent processing gives you an amazing power and flexibility when it comes to building highly available, scalable, and responsive applications capable of processing thousands of concurrent requests of various types.

Up until now you’ve been creating Java programs that were executing code sequentially. But the main power of Java lies in its ability to do things in parallel, or, as they say, to run multiple threads of execution. As always, going through a practical use case is the best way to understand this feature.

Let’s discuss a program that should display market news and information about the user’s stock portfolio in the same window. While the market news feed is coming from a remote computer, stock portfolio data are retrieved from the database and may be located on the local server of your organization.

Suppose it takes three seconds to get the market news and only one second to get the portfolio data. If you run these two tasks sequentially (one after another), you need four seconds to complete the job.

But market news doesn’t depend on your portfolio data, and these two tasks can run in parallel. They run on different computers and use different processors. If you can implement parallel processing, the total time should be less than four seconds (close to three seconds in the use case—the time it takes for the longer task to complete).

A Java program can start multiple threads of execution that will run in parallel. Even if you have only one processor in your computer, it still could be a good idea to run some tasks in parallel. Think of a web browser that allows you to download a file and perform page browsing at the same time. Web browsers maintain several connections to any website, and can download multiple resources (text, images, videos, music) at the same time. Any web browser works in a multithreaded mode.

If these jobs ran sequentially, the browser’s window would be frozen until the download was complete. On a multiprocessor computer, parallel threads can run on different CPUs. On a single-processor computer, threads take turns getting “slices” of the processor’s time. Because switching CPU cycles between threads happens fast, a user won’t notice the tiny delays in each thread’s execution, and browsing feels smooth.

In many cases, especially on the disappearing single-CPU computers, the benefit of many threads comes about because there’s a lot of idle time in most operations. In particular, if an operation is I/O bound instead of CPU bound then using multiple threads helps take advantage of those otherwise unused blocks of time.

People also can work in a multithreaded mode. For example, they can drink coffee while talking on a cell phone and driving a car.

The Class Thread

If class A needs to initiate some parallel executions in classes B and C, the latter two must declare multithreading support from the get-go. Each of the classes B and C must either be inherited from the Java class Thread or implement one of the following interfaces: Runnable or Callable (the latter is covered in Callable). If a class is inherited from the class Thread then it has to override the method run().

The first version of the market-portfolio example has three classes (see Listing 17-1, Listing 17-2, and Listing 17-3). Two of them are subclasses of the class Thread (MarketNews and Portfolio), and the third (TestThreads) is just a testing program that instantiates them and starts the execution of some code in each of them. You must initiate the code that has to work as a thread in the method run().

Listing 17-1: Class MarketNews

public class MarketNews extends Thread {

public MarketNews (String threadName) {

super(threadName); // name your thread

}

public void run() {

System.out.println("The stock market is improving!");

}

}

Listing 17-2: Class Portfolio

public class Portfolio extends Thread {

public Portfolio (String threadName) {

super(threadName);

}

public void run() {

System.out.println("You have 500 shares of IBM");

}

}

Listing 17-3: Class TestThreads starts MarketNews and Portfolio

public class TestThreads {

public static void main(String args[]){

MarketNews mn = new MarketNews("Market News");

mn.start();

Portfolio p = new Portfolio("Portfolio data");

p.start();

System.out.println("TestThreads is finished");

}

}

The method main() in Listing 17-3 instantiates each thread, passing the name for the thread as a constructor argument and then calls its start() method declared in its ancestor. Each thread itself invokes internally the code written by you in the method run(). After calling mn.start(), the programTestThread does not wait for its completion but immediately executes the lines that follow, creating and starting the thread Portfolio. Even if the code in the MarketNews.run() is lengthy and takes several seconds to execute, the Portfolio thread starts immediately.

If you run the TestThread program it prints the output from threads MarketNews and Portfolio almost simultaneously—there is no lengthy and time-consuming code in their run() methods. A bit later, in the section “Sleeping Threads”, you see how to emulate a lengthy execution. The output of the TestThread program can vary—it all depends on which thread finishes first.

The Interface Runnable

The second way to create threads is to implement a Runnable interface, which is a functional interface with a single method run(). In this case, your class also has to have business logic in the method run(). First, you see an old-fashioned version of creating a thread with Runnable, and then more concise version with lambda expressions.

The second version of our market-portfolio example (Listing 17-4, Listing 17-5, and Listing 17-6) also has three classes (you eliminate two of them shortly), but MarketNews2 and Portfolio2 are not inherited from the class Thread—they implement the Runnable interface.

In environments before Java 8, creation of a thread iis a two-step process: create an instance of a class that implements Runnable and then give it as an argument to the constructor of the class Thread during instantiation.

Listing 17-4: Class MarketNews2

public class MarketNews2 implements Runnable {

public void run() {

System.out.println("The stock market is improving!");

}

}

Listing 17-5: Class Portfolio2

public class Portfolio2 implements Runnable {

public void run() {

System.out.println("You have 500 shares of IBM ");

}

}

Listing 17-6: Class TestThreads2

public class TestThreads2 {

public static void main(String args[]){

MarketNews2 mn2 = new MarketNews2();

// passing Runnable object to a constructor

Thread mn = new Thread(mn2,"Market News");

mn.start();

Runnable port2 = new Portfolio2();

// passing Runnable object to a constructor

Thread p = new Thread(port2, "Portfolio Data");

p.start();

System.out.println("TestThreads2 is finished");

}

}

Run this program, and you see an output similar to this one:

The stock market is improving!

TestThreads2 is finished

You have 500 shares of IBM

The main thread finished earlier than the portfolio one!

Note that I’ve declared the variable port2 in Listing 17-6 to not be of type Portfolio2; instead it is type Runnable. I did it for illustration purposes and to reiterate the fact that an interface is also a data type that can be used in variable declarations. It takes three lines of code in Listing 17-6 to instantiate and start a thread. The Runnable interface provides a more flexible way to use threads because it allows a class to be inherited from any other class, while having all the features of a thread.

Eliminating Inheritance

In Lesson 13 in the Eliminating Inheritance section I demonstrated how an inheritance hierarchy can be simplified by introducing lambda expressions. Let’s do it again. The classes Portfolio2 and MarketNews2 differ only in the implementation of the method run()of the functional interface. You can easily get rid of both of these classes by providing implementation of the functional interface Runnable (the method run() )with lambda expressions directly to the constructors of the Thread objects.

public class TestThreads2Lambda {

public static void main(String args[]){

Thread mn = new Thread(()-> System.out.println(

"The stock market is improving!"),"Market News");

mn.start();

Thread p = new Thread(() -> System.out.println(

"You have 500 shares of IBM"),"Portfolio Data");

p.start();

System.out.println("TestThreads2Lambda is finished");

}

}

The classes MarketNews2 and Portfolio2 are not needed any longer! This example is very simplistic because both implementations of run() just print a simple message. You can also pass a multiline lambda expression; just don’t forget to declare the expression in curly braces. The nextsection includes an example.

Sleeping Threads

One of the ways to make the processor available to other threads is by using Thread’s method sleep(), which enables you to specify in milliseconds (and nanoseconds) how long the thread has to sleep. The next program demonstrates sleeping threads. The class TestThreads3Lambdas declares two lambda expressions to process market data and portfolio threads. The function for market news puts itself to sleep for a thousand milliseconds (one second) after each output of the message about market improvements.

When the market news thread goes to sleep, the portfolio gets the CPU and prints its message and then goes to sleep for 700 milliseconds on each loop iteration. Every second the market news thread wakes up and does its job. The portfolio thread has shorter sleep periods.

The program TestThreads3Lambda generates mixed console output about the market and portfolio from both threads—the threads are taking turns even on the single-processor machine.

Listing 17-7: Class TestThreads3Lambda

public class TestThreads3Lambda {

public static void main(String args[]){

// Lambda expression for Market News

Runnable mn = () -> {

try{

for (int i=0; i<10;i++){

Thread.sleep (1000); // sleep for 1 second

System.out.println("The market is improving " + i);

}

}catch(InterruptedException e ){

System.out.println(Thread.currentThread().getName()

+ e.toString());

}

};

Thread marketNews = new Thread(mn, "Market News");

marketNews.start();

// Lambda expression for Portfolio

Runnable port = () ->{

try{

for (int i=0; i<10;i++){

Thread.sleep (700); // Sleep for 700 milliseconds

System.out.println("You have " + (500 + i) +

" shares of IBM");

}

}catch(InterruptedException e ){

System.out.println(Thread.currentThread().getName()

+ e.toString());

}

};

Thread portfolio = new Thread(port,"Portfolio data");

portfolio.start();

System.out.println(

"The main method of TestThreads3Lambda is finished");

}

}

If you need to “wake up” a sleeping thread before its sleeping time is up, use the method interrupt(). Just add mn.interrupt() to the class TestThreads3Lambda right after starting the market news thread. This triggers InterruptedException, and the market news thread will wake up and continue its execution from the operator located below the sleep() method call. The class Thread has a method interrupted() that returns true if the current thread has been interrupted. The output of the program TestThreads3Lambda can look as follows:

The main method of TestThreads3Lambda is finished

You have 500 shares of IBM

The market is improving 0

You have 501 shares of IBM

The market is improving 1

You have 502 shares of IBM

You have 503 shares of IBM

The market is improving 2

You have 504 shares of IBM

The market is improving 3

You have 505 shares of IBM

You have 506 shares of IBM

The market is improving 4

You have 507 shares of IBM

The market is improving 5

You have 508 shares of IBM

The market is improving 6

You have 509 shares of IBM

The market is improving 7

The market is improving 8

The market is improving 9

These days it’s hard to find a single-CPU server machine. Most of the readers of this book have personal computers with dual-core CPUs, which have two processors in the same chip. Modern JVMs use multiple cores for multithreaded applications, but you shouldn’t assume that your program will run twice as fast on such hardware. JVM optimization is a complex subject and is out of the scope of this tutorial. You may boost the performance of your system by increasing the number of threads running in parallel, but you should define the right ratio between the number of threads and the number of processors (see Amdahl’s Law at http://en.wikipedia.org/wiki/Amdahl's_law) during the performance-tuning phase of application development.

How to Kill a Thread

The class Thread has a method, stop(), that was supposed to know how to kill the current thread. But it was deprecated many years ago because it could bring some of the objects in your program into an inconsistent state caused by improper unlocking of the object instances.

There are different approaches to killing threads. One of them involves creating your own method on the thread, say stopMe(), in which you set your own boolean variable, say stopMe, to false and test its value periodically inside the thread’s method run(). If application code changes the value of stopMe to true, just exit the code execution in the method run(). In Listing 17-8, the loop in the method run initializes the value of the variable stopMe with the reference to the current thread and then runs the infinite loop testing if the value of stopMe is still the same. As soon as it is changed (set to null in this case), the processing in the PortfolioVolatile stops.

Listing 17-8: Killing a thread

class KillTheThread{

public static void main(String args[]){

PortfolioVolatile p =new PortfolioVolatile("Portfolio data");

p.start();

// Some code implementation business logic goes here

int i=0;

do {

System.out.println(" i= " + i++);

}while (i<100);

// and now it's time to kill the thread

p.stopMe();

}

}

class PortfolioVolatile extends Thread{

private volatile Thread stopMe;

public PortfolioVolatile (String threadName) {

super(threadName);

}

public void stopMe() {

stopMe = null;

}

public void run() {

stopMe = Thread.currentThread();

while (stopMe == Thread.currentThread()) {

//Do some portfolio processing here

System.out.println("The Portfolio thread is running");

}

System.out.println("The Portfolio thread was killed");

}

}

Running the program KillTheThread produces the console output that can end as follows:

The Portfolio thread is running

i= 97

i= 98

i= 99

The Portfolio thread is running

The Portfolio thread was killed

The variable stopMe has been declared with a volatile keyword, which warns the Java compiler that another thread can modify it, and that this variable shouldn’t be cached in the CPU’s registers, so all threads must always see its fresh value. The class PortfolioVolatile could be written differently—the variable stopMe could be declared as boolean.

Not every thread can be killed using the code shown in Listing 17-8. What if a thread is not doing any processing at the moment, but is waiting for the user’s input? Call the method interrupt() on such a thread. Killing a thread by interrupting it may be the only technique you need to use in such cases.

If you need to kill a thread that’s busy doing some blocking I/O operations and the preceding methods of killing such a thread don’t work, try closing I/O streams. This causes IOException during the current read/write operation and the thread will be over.

If you’d like to read more comprehensive coverage of this subject, see Dr. Heinz Kabutz the Java Specialist’s newsletter Issue #56, available at www.javaspecialists.co.za/archive/Issue056.html.

Thread Priorities

Single-processor computers use a special scheduling algorithm that allocates processor time slices to the running threads based on their priorities. If Thread1 is using the processor and the higher-priority Thread2 wakes up, Thread1 is pushed aside and Thread2 gets the CPU. It is said thatThread2 preempts Thread1.

The class Thread has a method, setPriority(), that allows you to control its priority. There are 10 different priorities, which are final integer variables defined in the class Thread. Some of them are named constants MIN_PRIORITY, NORM_PRIORITY, and MAX_PRIORITY. Here’s an example of their usage:

Thread myThread = new Thread("Portfolio");

myThread.setPriority(Thread.NORM_PRIORITY + 1);

If two threads with the same priority need the processor, it’ll be given to one of them using an algorithm specific to the computer’s operating system.

Thread Synchronization and Race Conditions

During the design stage of a multithreaded application’s development, you should consider the possibility of a so-called race condition, which happens when multiple threads need to modify the same program resource at the same time (concurrently). The classic example is when a husband and wife are trying to withdraw cash from different ATMs at the same time.

Suppose the balance on their joint account is $120. If a Thread class is responsible for the validation as well as update of the balance of their bank account, there is a slight chance that if the validation starts at the same time it’ll approve withdrawal of $100 for the husband and $50 for the wife because the each of the validated amounts is less than the total. A moment later the husband’s thread withdraws $100, and a split second later the wife’s thread attempts to withdraw $50—it was validated, right? Unless these two processes were synchronized the couple would be able to withdraw a total of $150, leaving a negative balance in their account. This is an example of a race condition.

A special keyword, synchronized, prevents race conditions from happening. This keyword places a lock on an object instance (the monitor) to make sure that only one thread at a time has access to the synchronized code. The code in Listing 17-9 locks the entire method withdrawCash() so no other thread gets access to the specified portion of code until the current (locking) thread has finished its execution of withdrawCash(). In this example, both validation and balance update can be performed by only one thread at a time.

Listing 17-9: Declaring a synchronized method

class ATMProcessor extends Thread{

synchronized withdrawCash(int accountID, int amount){

// Some thread-safe code goes here, i.e., reading from

// a file or a database

// ...

boolean allowTransaction = validateWithdrawal(accountID,

amount);

if (allowTransaction){

updateBalance(accountID, amount, "Withdraw");

}

else {

System.out.println("Not enough money on the account");

}

}

}

The locks should be placed for the shortest possible time to avoid slowing down the program: That’s why synchronizing short blocks of code is preferable to synchronizing whole methods. Listing 17-10 shows how to synchronize only the portion of the code that may actually cause the race condition, rather then locking the entire method withdrawCash().

Listing 17-10: Declaring a synchronized block

class ATMProcessor extends Thread{

...

withdrawCash(int accountID, int amount){

// Some thread-safe code goes here, i.e., reading from

// a file or a database

...

synchronized(this) {

boolean allowTransaction=validateWithdrawal(accountID, amount);

if (allowTransaction){

updateBalance(accountID, amount, "Withdraw");

}

else {

System.out.println("Not enough money on the account");

}

}

}

}

When a synchronized block is executed, the section of the code in parentheses is locked and can’t be used by any other thread until the lock is released. Listing 17-10 locks the current instance of the class ATMProcessor (represented by the this key-word) only for the duration of thevalidateWithdrawal() and updateBalance() methods, which is a shorter period of time than locking withdrawCash() would take.

Although synchronized is a Java keyword, there is a more efficient API for locking the code. It’s called reentrantLock(), and you see it later in this lesson.

Thread States

A thread goes through various states during its life span. The class Thread has a method, getState(), that returns one of the values defined in the enumeration Thread.State.

· BLOCKED: Thread state for a thread that is blocked and waiting to enter or reenter a synchronized method or block of code

· NEW: Thread state for a thread that has been instantiated but not started yet

· RUNNABLE: Thread state for a runnable thread

· TERMINATED: Thread state for a terminated thread

· TIMED_WAITING: Thread state for a waiting thread with a specified waiting time

· WAITING: Thread state for a waiting thread

The class Thread has a method, isAlive(), that can help you to find out the status of the thread. If it returns true, the thread has been started and hasn’t died yet. If it returns false, the thread is either new or already dead.

Wait and Notify

The class Object also has some methods relevant to threads: wait(), notify(), and notifyAll(). The method notify() allows one waiting thread to notify another about some important event. Accordingly, notifyAll() sends notification to all waiting threads. Because every Java class is inherited from the class Object, these methods can be called on any object. There is one more important rule: Both the wait and notification must be done in a synchronized block holding the lock on the same object.

Let’s revisit our class TestThreads3Lambda, which spawns the threads for market news and portfolio. It has the following line at the end of the main() method:

System.out.println("The main method TestThreads3 is finished");

Run the program TestThreads3Lambda, and it prints something like this:

The main method of TestThreads3Lambda is finished

You have 500 shares of IBM

The market is improving 0

You have 501 shares of IBM

The market is improving 1

...

Note that the method main() did not wait for the portfolio and market news threads’ completion! The next code sample shows you how one thread can wait for a notification from another using wait(). To simplify the understanding of the example I’m using just two threads: the main thread and the market news one. The new class is called TestLambdaWaitNotify. I want to kill two birds with one stone and explain an interesting use case for lambdas, too. To make the main() method wait for notifications, it can include the following code fragment:

TestLambdaWaitNotify thisInstance = new TestLambdaWaitNotify();

synchronized (thisInstance) {

try{

thisInstance.wait(20000); // wait for up to 20 sec

} catch (InterruptedException e){

e.printStackTrace();

}

}

System.out.println(

"The main method of TestLambdaWaitNotify is finished");

The method call wait(20000) means “wait for up to 20 seconds.” The last println statement is executed either after 20 seconds or when the main thread receives notification of some important event, whichever comes first. Calling wait() without the argument would make the program wait for the notification until it arrives. Examples of important events are a price drop on the auction for items you’re interested in, the reopening of the airport after freezing rain, and the execution of your order to purchase 100 shares of IBM stock.

The difference between sleep() and wait() is that calling sleep(20000) puts a thread into a not-runnable state for exactly 20 seconds, although wait(20000) might mean that it will come back to a runnable state earlier.

Note that in the preceding example the main thread placed a lock on the instance of its own object— thisInstance. The other thread has to receive a reference to the same object to send the notification. If you were writing code in traditional object-oriented style, you could create a separate class implementing Runnable with a constructor that gets a reference to the parent thread for further notifications as shown here:

Listing 17-11: Notification example

class MarketNews implements Runnable {

Object parent;

MarketNews(Object whoToNotify){

parent=whoToNotify;

}

public void run(){

// Do some lengthy processing here

synchronized(parent){

parent.notify(); // send notification to the waiting thread

}

}

}

But I’d like to implement Runnable using a lambda expression and illustrate an interesting concept called closures.

Closures in Java

In functional languages like JavaScript, a closure is a nested function that knows the context where it was declared. In other words, during the invocation the nested function has access to variables from the outer one even though they were never declared inside the nested function. It’s easier to explain this concept by example, and I will implement the market news thread not as a separate class, but as a lambda expression:

Runnable mNews =() -> {

// Do something

// But who to notify????

};

This lambda gets the object of the inferred type Runnable, but how to pass it to yet another object, which is the reference to the parent thread to send notification to? You create an “outer function”—a method that takes a reference to the parent thread as an argument:

private Runnable getMktNewsRunnable(

Object whoToNotify){

return () -> {

// Do something

whoToNotify.notify();

};

}

This is an example of a method returning a lambda expression so the following statement is valid:

Runnable mktNewsRunnable = getMktNewsRunnable(this);

The value of the variable is just the code returned by the method getMktNewsRunnable(). It’s important to notice that this code just uses the variable whoToNotify from the outer method even though it was not declared inside the lambda expression! So the inner function “remembers” that when it was created, there was someone in the neighborhood named whoToNotify. This is the essence of the concept of closures, which remember the context they were declared in.

The variables from outer scope are inferred to be final and are immutable; you can’t modify them. Even though I never declared the variable whoToNotify as final, it is final.

Following is the complete version of the class TestLambdaWaitNotify that creates a thread using lambda and gets notification when that thread is done with the processing.

public class TestLambdaWaitNotify {

private static Runnable getMktNewsRunnable(Object whoToNotify){

// returning a closure

return () -> {

try{

for (int i=0; i<10;i++){

Thread.sleep (1000); // sleep for 1 second

System.out.println("The market is improving " + i);

}

synchronized(whoToNotify){

whoToNotify.notify(); // send notification to parent

}

}catch(InterruptedException e ){

System.out.println(Thread.currentThread().getName()

+ e.toString());

}

};

}

public static void main(String args[]){

TestLambdaWaitNotify thisInstance = new TestLambdaWaitNotify();

Runnable mktNewsRunnable = getMktNewsRunnable(thisInstance);

Thread marketNews = new Thread(mktNewsRunnable,"");

marketNews.start();

synchronized (thisInstance) {

try{

thisInstance.wait(20000); // wait for up to 20 sec

} catch (InterruptedException e){

e.printStackTrace();

}

}

System.out.println(

"The main method of TestLambdaWaitNotify is finished");

}

}

Now the message that the main method is finished is printed after the loop inside the market news ends. Hopefully it takes less than 20 seconds. You can remove this time interval and just call wait() to ensure that even on the slow computers the main thread waits for as long as needed.

Joining Threads

Now let’s consider a scenario in which you need to start multiple threads and continue program execution only when all threads are complete. You may have several threads that need to wait for each other’s completion. The Thread class has a method, join(), that you can use in this case.

Revisit the TestThreads3Lambda program shown in Listing 17-7. If you want to make sure that the main method (the main thread) is waiting until the other two threads are finished, you can use the method join(). The following code snippet shows the class TestThreads3LambdaJoin that links together three threads: main, portfolio, and market news.

Listing 17-12: Joining threads

public class TestThreads3LambdaJoin {

public static void main(String args[]){

// Lambda expression for Market News

Runnable mn = () -> {

try{

for (int i=0; i<10;i++){

Thread.sleep (1000); // sleep for 1 second

System.out.println("The market is improving " + i);

}

}catch(InterruptedException e ){

System.out.println(Thread.currentThread().getName()

+ e.toString());

}

};

// Lambda expression for Portfolio

Runnable port = () ->{

try{

for (int i=0; i<10;i++){

Thread.sleep (700); // Sleep for 700 milliseconds

System.out.println("You have " + (500 + i) +

" shares of IBM");

}

}catch(InterruptedException e ){

System.out.println(Thread.currentThread().getName()

+ e.toString());

}

};

Thread marketNews = new Thread(mn, "Market News");

Thread portfolio = new Thread(port,"Portfolio data");

marketNews.start();

portfolio.start();

try{

marketNews.join();

portfolio.join();

}catch (InterruptedException e){

e.printStackTrace();

}

System.out.println(

"The main method of TestThreads3LambdaJoin is finished");

}

}

Running the class TestThreads3LambdaJoin prints the outputs of market news and portfolio first, and only after the message that the main method is finished. The main thread waits for the other two by joining them.

Goodies From java.util.concurrent

The package java.util.concurrent has lots of goodies that make thread programming a lot more robust and flexible, and most importantly that increase the performance of multithreaded applications. This section highlights some of the must-know techniques, classes, and interfaces from this package. For detailed coverage of this subject get the book Java Concurrency in Practice by Brian Goetz et al. (Addison-Wesley, 2006).

ReentrantLock Versus Synchronized

The package java.util.concurrent.locks includes the class ReentrantLock, which can be used as a replacement for the synchronized keyword. Using it gives you more flexibility, and it can be used across methods. The idea is to place a lock (invoke lock()) before the section of your program that may cause a race condition, and to remove the lock afterward. The next code snippet is a revision of the code shown earlier in Listing 17-10:

private Lock accountLock = new ReentrantLock();

witdrawCash(int accountID, int amount){

// Some thread-safe code goes here, e.g. reading from

// a file or a database

accountLock.lock(); // place a lock here

try{

if (allowTransaction){

updateBalance(accountID, amount, “Withdraw”);

} else {

System.out.println(“Not enough money on the account”);

}

}finally {

accountLock.unlock(); //allow other threads to update balance

}

}

Note that the lock has to be removed in the finally section to ensure that unlocking always gets executed, even if there is an exception thrown from the try block. When the code is unlocked it can be given to one of the waiting threads. The class ReentrantLock has an overloaded constructor with a boolean argument—if you specify true while creating the lock, the control is given to the longest-waiting thread.

There is another useful class, Condition, that can be associated with the lock. This object enables a locked block of code to suspend its execution until other threads notify the current one that some condition has become true—for example, the bank account has enough funds now for you to make a withdrawal.

If you don’t need the flexibility offered by the ReentrantLock/Condition combo, just use the synchronized keyword with notify()/notifyAll() methods to control thread locking. Or, even better, see if using one of the concurrent collections (reviewed in the section “A Brief Review of Concurrent Collections”) can take care of all your locking needs so you don’t need to create explicit locks in your code.

Executor Framework

Creating threads by subclassing Thread or implementing Runnable works, but there are certain shortcomings to these approaches. First, the method run() cannot return a value. Second, an application may spawn so many threads that it can take up all the system resources, and if this happens the application will stop functioning. In other words, you need to be able to control the number of threads allowed for each application.

You can overcome the first shortcoming by using the Callable interface, and the second one by using classes from the Executor framework. The Executors class spawns the threads from Runnable objects, ExecutorService knows how to create Callable threads, and ScheduledExecutorServiceallows you to schedule threads for future execution.

The utility class Executors has static methods that enable you to create an appropriate executor. In particular, its method newFixedThreadPool() creates a pool of threads of a specified size. For example, Executors.newFixedThreadPool(5) gives you an instance of ExecutorService that automatically supports a pool of not more than five threads. If all five threads are busy when a request to create a new thread comes in, that request waits until one of the running threads completes. Using thread pools ensures that you can control system resources better.

If you need a thread to return some data on completion, create a class that implements the Callable interface and defines a method call() that plays the same role as run() in Runnable. In this case you need to create threads differently; the class Thread doesn’t take a Callable object as an argument. The class Executors comes to the rescue: it offers a number of static methods that create a thread from your Callable class and return the result of its execution packaged inside the special object implementing the interface Future.

The method call() is defined with a parameterized value (remember generics?):

public interface Callable <V>{

V call() throws Exception;

}

Accordingly, if some method needs to create a thread using Callable, the code should instantiate the Callable thread with a specific data type in place of <V>. For example, the thread Portfolio may return an Integer as a result of some processing in its call() method:

public class Portfolio implements Callable<Integer>{

public Integer call() {

// Perform some actions

return someInteger;

}

}

public class MarketData implements Callable<Integer>{

public Integer call() {

// Perform some actions

return someInteger;

}

}

One way to create a Future object is by submitting an instance of the Callable thread to the Executor. Call the function get() on the Future instance, and it blocks on the thread until its call() method returns the result:

//Threads’ results can be stored in the collection of Futures

List<Future<Integer>> threadResults=

new ArrayList<Future<Integer>>();

// Submit Callables for execution

threadResults.add(myExecutorService.submit(new Portfolio()));

threadResults.add(myExecutorService.submit(new MarketData()));

for (Future<Integer> future : threadResults) {

future.get();

}

Calling methods get() on several instances of the Future objects is equivalent to joining threads.

The process of spawning threads using Executors, Callable, and Future may go like this:

1. Declare and instantiate a class that implements the Callable interface, and program the business logic in its method call(). Alternatively, you can use a lambda expression because Callable is a functional interface.

2. Create an instance of the Future object.

3. Create an instance of an ExecutorService using Executors.newFixedThreadPool().

4. Call the function submit() on the ExecutorService, providing an instance of the Callable object (or lambda expression) as an argument.

5. Call the function get() on the Future object from Step 2. This function waits until the thread returns the result (or throws an exception).

6. Accept the result of the thread execution into a variable of the data type used in Step 1.

7. Call the function shutdown() on the ExecutorService from Step 3.

The following class TestCallableThreads creates a collection of Future objects—one per thread. Executors creates a pool of two threads, and each thread is submitted for execution. The method get() waits for the completion of each thread, and the result of each call() method is stored in the collection results. Lambda expressions implement Callable.

Listing 17-13: Spawning threads with the Executor framework

public class TestCallableThreads {

public static void main(String[] args)

throws InterruptedException, ExecutionException {

// Lambda expression for Market News

Callable<Integer> mn = () -> {

for (int i=0; i<10;i++){

Thread.sleep (1000); // sleep for 1 second

System.out.println("The market is improving " + i);

}

// Just return some number to illustrate return

return 12345;

};

// Lambda expression for Portfolio

Callable<Integer> port = () ->{

for (int i=0; i<10;i++){

Thread.sleep (700); // Sleep for 700 milliseconds

System.out.println("You have " + (500 + i) +

" shares of IBM");

}

// Just return some number

return 10;

};

//A placeholder for Future objects

List<Future<Integer>> futures =

new ArrayList<Future<Integer>>();

// A placeholder for results returned by threads

List<Integer> results = new ArrayList<Integer>();

final ExecutorService service =

Executors.newFixedThreadPool(2);

try {

futures.add(service.submit(port));

futures.add(service.submit(mn));

for (Future<Integer> future : futures) {

results.add(future.get());

}

} finally {

service.shutdown();

}

for (Integer res: results){

System.out.println("\nGot the result: " + res);

}

}

}

The output of this program is shown next. But if you change the number of threads in the pool from two to one, the program first prints all messages from the portfolio thread and only after that prints all messages from the market news.

You have 500 shares of IBM

The market is improving 0

You have 501 shares of IBM

The market is improving 1

You have 502 shares of IBM

You have 503 shares of IBM

The market is improving 2

You have 504 shares of IBM

The market is improving 3

The market is improving 4

Got the result: 10

Got the result: 12345

A Brief Review of Concurrent Collections

The package java.util.concurrent offers a number of data structures that simplify programming with threads. This section briefly names some of them.

Queues

The concept of a queue (First In First Out or FIFO) fits well in any process that involves asynchronous intra-object communications. Instead of object A trying to place a direct lock on object B, the former (also known as the producer) can place some data objects in a queue, and the latter (also known as the consumer) retrieves (dequeues) them from the queue asynchronously. Most importantly, the queues from the java.util.concurrent package are thread-safe, which means that you can add an object to a queue without worrying about race conditions.

If the queue is blocking, the thread also blocks while trying to add an object to a full queue or remove an object from an empty one. The following classes implement the BlockingQueue interface: LinkedBlockingQueue, ArrayBlockingQueue, SynchronousQueue, PriorityBlockingQueue, andDelayQueue. To add an object to a queue you can use such methods as add(), put(), and offer(). To retrieve an object from a queue use poll(), remove(), take(), or peek().

Unbound queues don’t place limitations on the number of elements. ConcurrentLinkedQueue is an example of such a queue.

Java has introduced a Deque interface for inserting and removing elements from both ends of the queue. The class LinkedBlockingDeque is a concurrent implementation of this interface.

Collections

Using concurrent collections is a recommended way of creating thread-safe data structures. Such collections include ConcurrentHashMap, ConcurrentSkipListMap, ConcurrentSkipListSet, CopyOnWriteArrayList, and CopyOnWriteArraySet. Java documentation describes when to use each of these collections. For example, a CopyOnWriteArrayList is preferable to a synchronized ArrayList when the expected number of reads and traversals is much greater than the number of updates to a list. These collections were written to minimize the time during which data is locked.

The utility class java.util.Collections has a number of static methods that create thread-safe collections. Their method names start with the word synchronized. For example, synchronizedList() takes a regular List (such as ArrayList) as an argument and makes it thread-safe. You can read more about Java Collections Framework in Oracle documentation at http://goo.gl/yknUje.

Finding a ready-to-use synchronized collection is better than writing synchronized blocks on your own. The chances are slim that you’ll write more efficient synchronization code than already exists in Java.

Swingworker Thread

Any Java Swing application spawns a number of threads. At the very minimum it runs the main application thread, the second thread captures system events, and the third one communicates with the graphical user interface (GUI). The application itself may spawn additional threads. But if more than one thread needs to update the user interface (UI) components, the changes may not be rendered properly, because Swing components were not made thread-safe to minimize the number of locks that hurt performance.

To avoid this problem, UI updates shouldn’t be made directly, but rather submitted to an event dispatch thread. Swing uses a single-threaded model, which means that all UI updates are rendered via a single thread.

Suppose your GUI application is written with Java Swing, and a click on JButton initiates some server-side data request that takes about 10 seconds to complete. You should never execute long requests in the event dispatch thread. If you do, then the UI will become frozen, as no updates can be made until the long running process releases the lock on the thread. Therefore, you need to start a separate thread for such a long process, and when it finishes, the program has to modify the GUI via the event dispatch thread.

For example, if the result of a button click has to update a JTextField, you may create a new thread in the button’s actionPerformed() method and, from within the run() method of this thread, update the text field. This will work most of the time, if there are no conflicts with other threads running in your application.

All UI-related Swing events (such as button clicks and window repaints) are placed in a special queue, and the object java.awt.EventQueue retrieves them from this queue. You should direct modification of the UI (the JTextField in our example) to this queue.

In the older version of Java, to ensure that all application-specific data would modify the GUI via this queue, developers used the method invokeLater() to ensure that UI changes were placed in the EventQueue:

SwingUtilities.invokeLater(

new Runnable(){

public void run(){

// Do some processing here

//... and then update the UI

myTextField.setText(someData);

}

}

);

You may use lambda to make the preceding code shorter. The class javax.swing.SwingWorker gives you a cleaner (though not necessarily simpler) means of dealing with the event dispatch thread. This thread class implements Runnable and Future, and so can be submitted to the Executor for execution and return a result.

Let’s say a Swing application needs to make a request to the server to get the market news information, which may take a couple of seconds. So that the UI isn’t frozen for these seconds, this request has to be performed in a background thread, and when the result is ready the UI has to be updated. To arrange this, create a subclass of SwingWorker and override its doInBackground() method, then instantiate it and call its execute() method, as in Listing 17-14.

Listing 17-14: Basic use of SwingWorker

class MarketNewsWorker extends SwingWorker <List<String>, String>{

@Override public List<String> doInBackground(){

// Make a request to the server and return a result,

// i.e., a list of Strings

return myListOfTextData;

}

// method method overrides go here

}

class TestMarketNews{

...

public static void main(String[] args){

new MarketNewsWorker().execute();

}

}

This code gives you a high-level picture, but there is more to executing the thread with SwingWorker. First, you probably noticed the unknown syntax element @Override, which is Java annotation stating that the method doInBackground() is being overridden. Adding the @Overrideannotation is not required here; it’s just an example of an annotation. You learn about annotations in Chapter 23.

Second, the class MarketNewsWorker uses generics and has two parameters, <List<String> and String>. The reason for this is that the overridden method doInBackground() might call the SwingWorker’s process() method, and will call its done() method on completion; this is where the UI is being updated. Two parameters indicate what types of data will be returned by doInBackground() and given to process() respectively.

Why might you consider calling the method process() during your thread execution? You might do it to support some kind of progress meter or other means of reporting the progress of long-running processes. If, for example, a long-running thread is reading a large file or performing some lengthy calculations, you might want to calculate the percentage of completion and report it to the calling Swing application.

You are not allowed to call the process() method directly, but have to call a method called publish(), which internally calls process(). Override process() to add some messages to the log file or update the progress meter. The code to display the result of the calculations on the UI should be written in the method done().

Listing 17-15 shows you a typical way to program with SwingWorker. I left out the details on purpose so you’d have something to do for this lesson’s homework.

Listing 17-15: A typical way to use SwingWorker

class MarketNewsWorker extends SwingWorker <List<String>, String>{

@Override public List<String> doInBackground(){

// Make a request to the server and return a result,

// i.e., a list of Strings

for (String news: someNewsCollection){

//process each news and report the progress

// ...

publish("Processed the news " + news); //this calls process()

}

return myListOfTextData;

}

@Override protected void process(String progressMessage){

// display the progress information here

}

@Override protected void done(){

// modify UI components here by calling get()

// Future’s get() gives you the result of

// the thread execution

}

}

class TestMarketNews{

public static void main(String[] args){

new MarketNewsWorker().execute();

}

}

You just completed a rather long and advanced lesson of this book. The subject definitely requires more research and practice. Some good content to read next is the lesson on concurrency in Oracle’s Java tutorial, which is at http://docs.oracle.com/javase/tutorial/essential/concurrency. As always, trying it hands-on will deepen your understanding.

Try It

Create a Swing application with the GUI that consists of two JTextArea controls and one JButton with the label “Get the News.” Prepare two text files with some text information (the news), and write the code that reads them to the left and right text areas respectively. File reading has to be implemented concurrently using two SwingWorker threads.

Lesson Requirements

You should have Java installed.

NOTE You can download the code and resources for this “Try It” from the book’s web page atwww.wrox.com/go/javaprog24hr2e. You can find them in the Lesson17.zip.

Step-by-Step

1. Create a new Eclipse project.

2. Create a class called NewsReader as a subclass of SwingWorker. This class should have a constructor that takes one argument of type File, and another of type JTextArea (the content of the file should be displayed there).

3. Prepare two text files with some news in each.

4. Create a Swing application with two text areas and a button.

5. On the click of the button instantiate two NewsReader threads. Each thread should get an instance of the File object pointing to the corresponding news file and the corresponding text area.

6. Override the NewsReader’s methods doInBackground() and done() to read the files and populate the Swing view.

7. Test this program.

8. This step is optional. Override the method process() and make sure that it updates the view with progress information about the reading process. The progress should be displayed as a percentage: The percentage formula is progressToDisplay=readBytes/FileSize*100. Use the Swing classJProgressBar for displaying the progress bar.

TIP Please select the videos for Lesson 17 online at www.wrox.com/go/javaprog24hr2e. You will also be able to download the code and resources for this lesson from the website.