Book Image

Java 9 Concurrency Cookbook, Second Edition - Second Edition

By : Javier Fernández González
Book Image

Java 9 Concurrency Cookbook, Second Edition - Second Edition

By: Javier Fernández González

Overview of this book

Writing concurrent and parallel programming applications is an integral skill for any Java programmer. Java 9 comes with a host of fantastic features, including significant performance improvements and new APIs. This book will take you through all the new APIs, showing you how to build parallel and multi-threaded applications. The book covers all the elements of the Java Concurrency API, with essential recipes that will help you take advantage of the exciting new capabilities. You will learn how to use parallel and reactive streams to process massive data sets. Next, you will move on to create streams and use all their intermediate and terminal operations to process big collections of data in a parallel and functional way. Further, you’ll discover a whole range of recipes for almost everything, such as thread management, synchronization, executors, parallel and reactive streams, and many more. At the end of the book, you will learn how to obtain information about the status of some of the most useful components of the Java Concurrency API and how to test concurrent applications using different tools.
Table of Contents (12 chapters)

Creating, running, and setting the characteristics of a thread

In this recipe, we will learn how to do basic operations over a thread using the Java API. As with every element in the Java language, threads are objects. We have two ways of creating a thread in Java:

  • Extending the Thread class and overriding the run() method.
  • Building a class that implements the Runnable interface and the run() method and then creating an object of the Thread class by passing the Runnable object as a parameter--this is the preferred approach and it gives you more flexibility.

In this recipe, we will use the second approach to create threads. Then, we will learn how to change some attributes of the threads. The Thread class saves some information attributes that can help us identify a thread, know its status, or control its priority. These attributes are:

  • ID: This attribute stores a unique identifier for each thread.
  • Name: This attribute stores the name of the thread.
  • Priority: This attribute stores the priority of the Thread objects. In Java 9, threads can have priority between 1 and 10, where 1 is the lowest priority and 10 is the highest. It's not recommended that you change the priority of the threads. It's only a hint to the underlying operating system and it doesn't guarantee anything, but it's a possibility that you can use if you want.
  • Status: This attribute stores the status of a thread. In Java, a thread can be present in one of the six states defined in the Thread.State enumeration: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, or TERMINATED. The following is a list specifying what each of these states means:
    • NEW: The thread has been created and it has not yet started
    • RUNNABLE: The thread is being executed in the JVM
    • BLOCKED: The thread is blocked and it is waiting for a monitor
    • WAITING: The thread is waiting for another thread
    • TIMED_WAITING: The thread is waiting for another thread with a specified waiting time
    • TERMINATED: The thread has finished its execution

In this recipe, we will implement an example that will create and run 10 threads that would calculate the prime numbers within the first 20,000 numbers.

Getting ready

The example for this recipe has been implemented using the Eclipse IDE. If you use Eclipse or a different IDE, such as NetBeans, open it and create a new Java project.

How to do it...

Follow these steps to implement the example:

  1. Create a class named Calculator that implements the Runnable interface:
        public class Calculator implements Runnable {
  1. Implement the run() method. This method will execute the instructions of the thread we are creating, so this method will calculate the prime numbers within the first 20000 numbers:
        @Override 
public void run() {
long current = 1L;
long max = 20000L;
long numPrimes = 0L;

System.out.printf("Thread '%s': START\n",
Thread.currentThread().getName());
while (current <= max) {
if (isPrime(current)) {
numPrimes++;
}
current++;
}
System.out.printf("Thread '%s': END. Number of Primes: %d\n",
Thread.currentThread().getName(), numPrimes);
}
  1. Then, implement the auxiliar isPrime() method. This method determines whether a number is a prime number or not:
        private boolean isPrime(long number) { 
if (number <= 2) {
return true;
}
for (long i = 2; i < number; i++) {
if ((number % i) == 0) {
return false;
}
}
return true;
}
  1. Now implement the main class of the application. Create a class named Main that contains the main() method:
        public class Main { 
public static void main(String[] args) {
  1. First, write some information regarding the values of the maximum, minimum, and default priority of the threads:
        System.out.printf("Minimum Priority: %s\n",
Thread.MIN_PRIORITY);
System.out.printf("Normal Priority: %s\n",
Thread.NORM_PRIORITY);
System.out.printf("Maximun Priority: %s\n",
Thread.MAX_PRIORITY);
  1. Then create 10 Thread objects to execute 10 Calculator tasks. Also, create two arrays to store the Thread objects and their statuses. We will use this information later to check the finalization of the threads. Execute five threads (the even ones) with maximum priority and the other five with minimum priority:
        Thread threads[]; 
Thread.State status[];
threads = new Thread[10];
status = new Thread.State[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(new Calculator());
if ((i % 2) == 0) {
threads[i].setPriority(Thread.MAX_PRIORITY);
} else {
threads[i].setPriority(Thread.MIN_PRIORITY);
}
threads[i].setName("My Thread " + i);
}
  1. We are going to write information in a text file, so create a try-with-resources statement to manage the file. Inside this block of code, write the status of the threads in the file before you launch them. Then, launch the threads:
        try (FileWriter file = new FileWriter(".\\data\\log.txt");
PrintWriter pw = new PrintWriter(file);) {

for (int i = 0; i < 10; i++) {
pw.println("Main : Status of Thread " + i + " : " +
threads[i].getState());
status[i] = threads[i].getState();
}
for (int i = 0; i < 10; i++) {
threads[i].start();
}
  1. After this, wait for the finalization of the threads. As we will learn in the Waiting for the finalization of a thread recipe of this chapter, we can use the join() method to wait for this to happen. In this case, we want to write information about the threads when their statuses change, so we can't use this method. We use this block of code:
            boolean finish = false; 
while (!finish) {
for (int i = 0; i < 10; i++) {
if (threads[i].getState() != status[i]) {
writeThreadInfo(pw, threads[i], status[i]);
status[i] = threads[i].getState();
}
}

finish = true;
for (int i = 0; i < 10; i++) {
finish = finish && (threads[i].getState() ==
State.TERMINATED);
}
}

} catch (IOException e) {
e.printStackTrace();
}
}
  1. In the previous block of code, we called the writeThreadInfo() method to write information about the status of a thread in the file. This is the code for this method:
        private static void writeThreadInfo(PrintWriter pw,
Thread thread,
State state) {
pw.printf("Main : Id %d - %s\n", thread.getId(),
thread.getName());
pw.printf("Main : Priority: %d\n", thread.getPriority());
pw.printf("Main : Old State: %s\n", state);
pw.printf("Main : New State: %s\n", thread.getState());
pw.printf("Main : ************************************\n");
}
  1. Run the program and see how the different threads work in parallel.

How it works...

The following screenshot shows the console part of the output of the program. We can see that all the threads we have created run in parallel to do their respective jobs:

In this screenshot, you can see how threads are created and how the ones with an even number are executed first, as they have the highest priority, and the others executed later, as they have minimum priority. The following screenshot shows part of the output of the log.txt file where we write information about the status of the threads:

Every Java program has at least one execution thread. When you run the program, JVM runs the execution thread that calls the main() method of the program.

When we call the start() method of a Thread object, we are creating another execution thread. Our program will have as many execution threads as the number of calls made to the start() method.

The Thread class has attributes to store all of the information of a thread. The OS scheduler uses the priority of threads to select the one that uses the CPU at each moment and actualizes the status of every thread according to its situation.

If you don't specify a name for a thread, JVM automatically assigns it one in this format: Thread-XX, where XX is a number. You can't modify the ID or status of a thread. The Thread class doesn't implement the setId() and setStatus() methods as these methods introduce modifications in the code.

A Java program ends when all its threads finish (more specifically, when all its non-daemon threads finish). If the initial thread (the one that executes the main() method) ends, the rest of the threads will continue with their execution until they finish. If one of the threads uses the System.exit() instruction to end the execution of the program, all the threads will end their respective execution.

Creating an object of the Thread class doesn't create a new execution thread. Also, calling the run() method of a class that implements the Runnable interface doesn't create a new execution thread. Only when you call the start() method, a new execution thread is created.

There's more...

As mentioned in the introduction of this recipe, there is another way of creating a new execution thread. You can implement a class that extends the Thread class and overrides the run() method of this class. Then, you can create an object of this class and call the start() method to have a new execution thread.

You can use the static method currentThread() of the Thread class to access the thread object that is running the current object.

You have to take into account that the setPriority() method can throw an IllegalArgumentException exception if you try to establish priority that isn't between 1 and 10.

See also

  • The Creating threads through a factory recipe of this chapter