Writing concurrent and parallel programming applications is a crucial skill for any Java programmer. Java 9 comes with a host of fantastic features, including significant performance improvements and new APIs. This video will take you through all the new APIs, showing you how to build parallel and multi-threaded applications. The video 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 video, 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.
About the Author
Javier Fernández González is a software architect with almost 15 years experience in Java technologies. He has worked as a teacher, researcher, programmer, analyst, and writer, and he now works as an architect in all types of projects related to Java, especially J2EE. As a teacher has over 1,000 hours of training in basic Java, J2EE, and the Struts framework. As a researcher, he has worked in the field of information retrieval, developing applications for processing large amounts of data in Java, and has participated as a co-author in several journal articles and conference presentations. Recently, he worked on developing J2EE web applications for various clients from different sectors (public administration, insurance, healthcare, transportation, and so on). He has also worked as a software architect. He is the author of the books, Java 7 Concurrency Cookbook and Mastering Concurrency Programming with Java 8 by Packt.
When we want to finish the execution of an executor, we use the shutdown() method. The executor waits for the completion of tasks that are either running or waiting for their execution. The ThreadPoolExecutor class provides a mechanism, which is called when a task is rejected.
One of the advantages of the Executor framework is that it allows you to run concurrent tasks that return a result. The Java Concurrency API achieves this with Callable and Future interfaces.
A common problem in concurrent programming arises when you have various concurrent tasks available to solve a problem. You have various sort of algorithms. You can launch all of them and get the result of the first one that sorts the array, that is, the fastest sorting algorithm for a given array.
When you want to wait for the finalization of a task, you can use the isDone() and awaitTermination() methods. These two methods have some drawbacks. The ThreadPoolExecutor class provides a method that allows you to send a list of tasks to the executor and wait for the finalization of all the tasks in the list.
There are use cases when you are not interested in executing a task as soon as possible. You may want to execute a task after a period of time or do it periodically; the Executor framework provides the ScheduledExecutorService interface along with its implementation, namely, the ScheduledThreadPoolExecutor class.
The Executor framework provides the ThreadPoolExecutor class to execute concurrent tasks using a pool of threads that helps you avoid all thread creation operations.
When you want to cancel a task that you send to the executor, you can use the cancel() method of Future, which allows you to make the cancelation operation.
The Java API provides the FutureTask class as a cancelable asynchronous computation. It implements the Runnable and Future interfaces and provides the basic implementation of the Future interface.
When you execute concurrent tasks using an executor, you will send Runnable or Callable tasks to the executor and get Future objects to control the method. For such situations, the Java Concurrency API provides the CompletionService class.
The basic elements of the fork/join framework are creating a ForkJoinPool object to execute the tasks and creating a subclass of ForkJoinTask to be executed in the pool.
The fork/join framework provides the ability to execute tasks that return a result.
In this video, you will learn how to use the asynchronous methods provided by the ForkJoinPool and CountedCompleter classes for the management of tasks.
The behavior of the ForkJoinTask and ForkJoinPool classes is different. The program doesn't finish execution, and you won't see any information about the exception in the console. In this video, you will learn the techniques to get that information.
When you execute the ForkJoinTask objects in a ForkJoinPool class, you can cancel them before they start their execution. The ForkJoinTask class provides the cancel() Method.
In this video, you will learn how to create streams from different sources.
In this video, you will learn how to use the different versions of the reduce() method to generate a result from a stream of values.
In this video, we will learn how to execute collect operations in Java streams with the different versions of the collect() method and the auxiliary Collectors class.
In this video, you will learn to apply an action to all the elements of the stream. We will use three methods: two terminal operations, the forEach() and forEachOrdered(), and an intermediate operation, the peek() method.
One of the most commons actions you will apply to a stream will be the filtering operation that selects the elements that continue with the processing. In this recipe, you will learn the different methods provided by the Stream class to select the elements of a stream.
Some of the intermediate operations that can be used with streams are those that allow you to transform the elements of the stream. In this video, you will learn to use the transforming intermediate operations.
Another typical operation you will want to perform with a Stream is sorting its elements. You can speed up the execution by deleting the ordering constraint.
One interesting option provided by the Stream class is the possibility to check whether the elements of the stream verify a condition or not.
Java 9 has included three interfaces: the Flow.Publisher, the Flow.Subscriber, and the Flow.Subscription, and a utility class, the
SubmissionPublisher class, to allow us to implement reactive stream applications.
A deque is a data structure similar to a queue, but you can add or remove elements from either the front (head) or back (tail) in a deque. In this video, you will learn how to use a non-blocking deque in a concurrent program.
The main difference between blocking deques and non-blocking deques is that blocking deques have methods to insert and delete elements that, if not done immediately. Java includes the LinkedBlockingDeque class that implements a blocking deque.
Another important characteristic of PriorityBlockingQueue is that it's a blocking data structure. It has methods that, if unable to perform the operation immediately, will block the thread until they are able to do it.
An interesting data structure provided by the Java API, which you can use in concurrent applications, is implemented in the DelayQueue class. In this program, we will learn to use the DelaydQueue class by storing in it some events with different activation dates.
The Java API provides a class that implements ConcurrentSkipListMap, which is the interface that implements a non-blocking list with the behavior of the ConcurrentNavigableMap interface.
A hash table is a data structure that allows you to map a key to a value. The Java API provides different hash table implementations through the Map and ConcurrentMap interfaces.
Java introduced atomic variables. When a thread is performing an operation with an atomic variable and if other threads want to do an operation with the same variable, the implementation of the class includes a mechanism to check that the operation is done atomically.
Java introduced atomic arrays that provide atomic operations for arrays of integer or long numbers. In this video, you will learn to use the AtomicIntegerArray class to work with atomic arrays.
In multithread applications, concurrent threads run in different CPUs or cores inside a CPU. To solve this problem, the Java language includes the volatile keyword.
Variable handles are a new feature of Java 9 that allow you to get a typed reference to a variable. You can use variable handles to obtain the same functionality without using any synchronization mechanism. A variable handle also allows you to get additional access modes to a variable.
Packt has been committed to developer learning since 2004. A lot has changed in software since then - but Packt has remained responsive to these changes, continuing to look forward at the trends and tools defining the way we work and live. And how to put them to work.
With an extensive library of content - more than 4000 books and video courses -Packt's mission is to help developers stay relevant in a rapidly changing world. From new web frameworks and programming languages, to cutting edge data analytics, and DevOps, Packt takes software professionals in every field to what's important to them now.
From skills that will help you to develop and future proof your career to immediate solutions to every day tech challenges, Packt is a go-to resource to make you a better, smarter developer.
Packt Udemy courses continue this tradition, bringing you comprehensive yet concise video courses straight from the experts.