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)

Grouping threads and processing uncontrolled exceptions in a group of threads

An interesting functionality offered by the concurrency API of Java is the ability to group threads. This allows us to treat the threads of a group as a single unit and provide access to the thread objects that belong to a group in order to do an operation with them. For example, you have some threads doing the same task and you want to control them. You can, for example, interrupt all the threads of the group with a single call.

Java provides the ThreadGroup class to work with a groups of threads. A ThreadGroup object can be formed by thread objects and another ThreadGroup object, generating a tree structure of threads.

In the Controlling the interruption of a thread recipe, you learned how to use a generic method to process all the uncaught exceptions that are thrown in a thread object. In the Processing uncontrolled exceptions in a thread recipe, we wrote a handler to process the uncaught exceptions thrown by a thread. We can use a similar mechanism to process the uncaught exceptions thrown by a thread or a group of threads.

In this recipe, we will learn to work with ThreadGroup objects and how to implement and set the handler that would process uncaught exceptions in a group of threads. We'll do this using an example.

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. First, extend the ThreadGroup class by creating a class called MyThreadGroup that would be extended from ThreadGroup. You have to declare a constructor with one parameter because the ThreadGroup class doesn't have a constructor without it. Extend the ThreadGroup class to override the uncaughtException() method in order to process the exceptions thrown by the threads of the group:
        public class MyThreadGroup extends ThreadGroup { 
public MyThreadGroup(String name) {
super(name);
}
  1. Override the uncaughtException() method. This method is called when an exception is thrown in one of the threads of the ThreadGroup class. In this case, the method will write information about the exception and the thread that throws it; it will present this information in the console. Also, note that this method will interrupt the rest of the threads in the ThreadGroup class:
        @Override 
public void uncaughtException(Thread t, Throwable e) {
System.out.printf("The thread %s has thrown an Exception\n",
t.getId());
e.printStackTrace(System.out);
System.out.printf("Terminating the rest of the Threads\n");
interrupt();
}
  1. Create a class called Task and specify that it implements the Runnable interface:
        public class Task implements Runnable {
  1. Implement the run() method. In this case, we will provoke an AritmethicException exception. For this, we will divide 1,000 with random numbers until the random generator generates zero to throw the exception:
        @Override 
public void run() {
int result;
Random random=new Random(Thread.currentThread().getId());
while (true) {
result=1000/((int)(random.nextDouble()*1000000000));
if (Thread.currentThread().isInterrupted()) {
System.out.printf("%d : Interrupted\n",
Thread.currentThread().getId());
return;
}
}
}
  1. Now, implement the main class of the example by creating a class called Main and implement the main() method:
        public class Main { 
public static void main(String[] args) {
  1. First, calculate the number of threads you are going to launch. We use the availableProcessors() method of the Runtime class (we obtain the runtime object associated with the current Java application with the static method, called getRuntime(), of that class). This method returns the number of processors available to the JVM, which is normally equal to the number of cores of the computer that run the application:
        int numberOfThreads = 2 * Runtime.getRuntime()
.availableProcessors();
  1. Create an object of the MyThreadGroup class:
        MyThreadGroup threadGroup=new MyThreadGroup("MyThreadGroup");
  1. Create an object of the Task class:
        Task task=new Task();
  1. Create the calculated number of Thread objects with this Task class and start them:
        for (int i = 0; i < numberOfThreads; i++) { 
Thread t = new Thread(threadGroup, task);
t.start();
}
  1. Then, write information about ThreadGroup in the console:
        System.out.printf("Number of Threads: %d\n",
threadGroup.activeCount());
System.out.printf("Information about the Thread Group\n");
threadGroup.list();
  1. Finally, write the status of the threads that form the group:
            Thread[] threads = new Thread[threadGroup.activeCount()]; 
threadGroup.enumerate(threads);
for (int i = 0; i < threadGroup.activeCount(); i++) {
System.out.printf("Thread %s: %s\n", threads[i].getName(),
threads[i].getState());
}
}
}
  1. Run the example and see the results.

How it works...

In the following screenshot, you can see the output of the list() method of the ThreadGroup class and the output generated when we write the status of each Thread object:

The ThreadGroup class stores thread objects and other ThreadGroup objects associated with it so it can access all of their information (status, for example) and perform operations over all its members (interrupt, for example).

Check out how one of the thread objects threw the exception that interrupted the other objects:

When an uncaught exception is thrown in a Thread object, the JVM looks for three possible handlers for this exception.

First, it looks for the uncaught exception handler of the thread, as explained in the Processing uncontrolled exceptions in a thread recipe. If this handler doesn't exist, then the JVM looks for the uncaught exception handler of the ThreadGroup class of the thread, as learned in this recipe. If this method doesn't exist, the JVM looks for the default uncaught exception handler, as explained in the Processing uncontrolled exceptions in a thread recipe.

If none of the handlers exists, the JVM writes the stack trace of the exception in the console and ends the execution of the thread that had thrown the exception.

See also

  • The Processing uncontrolled exceptions in a thread recipe