39,59 €
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.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 626
Veröffentlichungsjahr: 2017
BIRMINGHAM - MUMBAI
Copyright © 2017 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
First published: October 2012
Second edition: April 2017
Production reference: 1170417
ISBN 978-1-78712-441-7
www.packtpub.com
Author
Javier Fernández González
Copy Editor
Gladson Monteiro
Reviewer
Piotr Bzdyl
Project Coordinator
Vaidehi Sawant
Commissioning Editor
Kunal Parikh
Proofreader
Safis Editing
Acquisition Editor
Denim Pinto
Indexer
Tejal Daruwale Soni
C
ontent
De
velopment
Editor
Nikhil Borkar
Graphics
Abhinash Sahu
Technical Editor
Subhalaxmi Nadar
Production Coordinator
Melwyn Dsa
Javier Fernández González is a software architect with almost 15 years of 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 taken 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 coauthor 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). Currently, he works as a software architect. He is the author of the book, Java 7 Concurrency Cookbook and Mastering Concurrency Programming with Java 8 by Packt.
Piotr Bzdyl is focused on Java concurrency topics, including other JVM languages and their libraries, aimed at helping in creating highly concurrent applications (async IO, non-blocking APIs, Scala, Akka, and Clojure). He has been helping teams with JVM tuning and troubleshooting.
He has also created a training course for Java concurrency topics, covering core JDK multithreading concepts as well as those from external libraries and languages (actors, STM, parallel collections, and functional languages).
You can connect with Piotr on LinkedIn at https://www.linkedin.com/in/piotrbzdyl and on GitHub at https://github.com/pbzdyl. You can follow him on Stack Overflow at http://stackoverflow.com/cv/piotrekbzdyl.
For support files and downloads related to your book, please visit www.PacktPub.com.
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.comand as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks.
https://www.packtpub.com/mapt
Get the most in-demand software skills with Mapt. Mapt gives you full access to all Packt books and video courses, as well as industry-leading tools to help you plan your personal development and advance your career.
Fully searchable across every book published by Packt
Copy and paste, print, and bookmark content
On demand and accessible via a web browser
Thanks for purchasing this Packt book. At Packt, quality is at the heart of our editorial process. To help us improve, please leave us an honest review on this book's Amazon page at https://www.amazon.com/dp/178712441X.
If you'd like to join our team of regular reviewers, you can e-mail us at [email protected]. We award our regular reviewers with free eBooks and videos in exchange for their valuable feedback. Help us be relentless in improving our products!
Preface
What this book covers
What you need for this book
Who this book is for
Sections
Getting ready
How to do it…
How it works…
There's more…
See also
Conventions
Reader feedback
Customer support
Downloading the example code
Errata
Piracy
Questions
Thread Management
Introduction
Creating, running, and setting the characteristics of a thread
Getting ready
How to do it...
How it works...
There's more...
See also
Interrupting a thread
Getting ready
How to do it...
How it works...
There's more...
Controlling the interruption of a thread
Getting ready
How to do it...
How it works...
There's more...
See also
Sleeping and resuming a thread
Getting ready
How to do it...
How it works...
There's more...
Waiting for the finalization of a thread
Getting ready
How to do it...
How it works...
There's more...
Creating and running a daemon thread
Getting ready
How to do it...
How it works...
There's more...
Processing uncontrolled exceptions in a thread
Getting ready
How to do it...
How it works...
There's more...
See also
Using thread local variables
Getting ready
How to do it...
How it works...
There's more...
Grouping threads and processing uncontrolled exceptions in a group of threads
Getting ready
How to do it...
How it works...
See also
Creating threads through a factory
Getting ready
How to do it...
How it works...
See also
Basic Thread Synchronization
Introduction
Synchronizing a method
Getting ready
How to do it...
How it works...
There's more...
See also
Using conditions in synchronized code
Getting ready
How to do it...
How it works...
There's more...
See also
Synchronizing a block of code with a lock
Getting ready
How to do it...
How it works...
There's more...
Avoiding deadlocks
See also
Synchronizing data access with read/write locks
Getting ready...
How to do it...
How it works...
See also
Using multiple conditions in a lock
Getting ready
How to do it...
How it works...
There's more...
See also
Advanced locking with the StampedLock class
Getting ready
How to do it...
How it works...
There's more...
See also
Thread Synchronization Utilities
Introduction
Controlling concurrent access to one or more copies of a resource
Getting ready
How to do it...
How it works...
There's more...
Fairness in semaphores
See also
Waiting for multiple concurrent events
Getting ready
How to do it...
How it works...
There's more...
Synchronizing tasks in a common point
Getting ready
How to do it...
How it works...
There's more...
Resetting a CyclicBarrier object
Broken CyclicBarrier objects
See also
Running concurrent-phased tasks
Getting ready
How to do it...
How it works...
There's more...
Registering participants in Phaser
Forcing the termination of Phaser
See also
Controlling phase change in concurrent-phased tasks
Getting ready
How to do it...
How it works...
See also
Exchanging data between concurrent tasks
Getting ready
How to do it...
How it works...
There's more...
Completing and linking tasks asynchronously
Getting ready
How to do it...
How it works...
There's more...
See also...
Thread Executors
Introduction
Creating a thread executor and controlling its rejected tasks
Getting ready
How to do it...
How it works...
There's more...
See also
Executing tasks in an executor that returns a result
Getting ready
How to do it...
How it works...
There's more...
See also
Running multiple tasks and processing the first result
Getting ready
How to do it...
How it works...
There's more...
See also
Running multiple tasks and processing all the results
Getting ready
How to do it...
How it works...
There's more...
See also
Running a task in an executor after a delay
Getting ready
How to do it...
How it works...
There's more...
See also
Running a task in an executor periodically
Getting ready
How to do it...
How it works...
There's more...
See also
Canceling a task in an executor
Getting ready
How to do it...
How it works...
There's more...
See also
Controlling a task finishing in an executor
Getting ready
How to do it...
How it works...
See also
Separating the launching of tasks and the processing of their results in an executor
Getting ready
How to do it...
How it works...
There's more...
See also
Fork/Join Framework
Introduction
Creating a fork/join pool
Getting ready
How to do it...
How it works...
There's more...
See also
Joining the results of the tasks
How to do it...
How it works...
There's more...
See also
Running tasks asynchronously
How to do it...
How it works...
There's more...
See also
Throwing exceptions in the tasks
Getting ready
How to do it...
How it works...
There's more...
See also
Canceling a task
Getting ready...
How to do it...
How it works...
See also
Parallel and Reactive Streams
Introduction
Creating streams from different sources
Getting ready
How to do it...
How it works...
There's more...
See also
Reducing the elements of a stream
Getting ready
How to do it...
How it works...
There's more...
See also
Collecting the elements of a stream
Getting ready
How to do it...
How it works...
There's more...
See also
Applying an action to every element of a stream
Getting ready
How to do it...
How it works...
There's more...
See also
Filtering the elements of a stream
Getting ready
How to do it...
How it works...
There's more...
See also
Transforming the elements of a stream
Getting ready
How to do it...
How it works...
There's more...
See also
Sorting the elements of a stream
Getting ready
How to do it...
How it works...
There's more...
See also
Verifying conditions in the elements of a stream
Getting ready
How to do it...
How it works...
There's more...
See also
Reactive programming with reactive streams
Getting ready
How to do it...
How it works...
There's more...
Concurrent Collections
Introduction
Using non-blocking thread-safe deques
Getting ready
How to do it...
How it works...
There's more...
Using blocking thread-safe deques
Getting ready
How to do it...
How it works...
There's more...
See also
Using blocking thread-safe queue ordered by priority
Getting ready
How to do it...
How it works...
There's more...
See also
Using thread-safe lists with delayed elements
Getting ready
How to do it...
How it works...
There's more...
See also
Using thread-safe navigable maps
Getting ready
How to do it...
How it works...
There's more...
See also
Using thread-safe HashMaps
Getting ready
How to do it...
How it works...
There's more...
See also
Using atomic variables
Getting ready
How to do it...
How it works...
There's more...
See also
Using atomic arrays
Getting ready
How to do it...
How it works...
There's more...
See also
Using the volatile keyword
Getting ready
How to do it...
How it works...
There's more...
See also
Using variable handles
Getting ready
How to do it...
How it works...
There's more...
See also
Customizing Concurrency Classes
Introduction
Customizing the ThreadPoolExecutor class
Getting ready
How to do it...
How it works...
See also
Implementing a priority-based Executor class
Getting ready
How to do it...
How it works...
There's more...
See also
Implementing the ThreadFactory interface to generate custom threads
Getting ready
How to do it...
How it works...
There's more...
Using our ThreadFactory in an Executor object
Getting ready
How to do it...
How it works...
See also
Customizing tasks running in a scheduled thread pool
Getting ready
How to do it...
How it works...
There's more...
See also
Implementing the ThreadFactory interface to generate custom threads for the fork/join framework
Getting ready
How to do it...
How it works...
There's more...
See also
Customizing tasks running in the fork/join framework
How to do it...
How it works...
See also
Implementing a custom Lock class
Getting ready
How to do it...
How it works...
There's more...
See also
Implementing a transfer queue-based on priorities
Getting ready
How to do it...
How it works...
See also
Implementing your own atomic object
Getting ready
How to do it...
How it works...
See also
Implementing your own stream generator
Getting ready
How to do it...
How it works...
There's more...
See also
Implementing your own asynchronous stream
Getting ready
How to do it...
How it works...
There's more...
See also
Testing Concurrent Applications
Introduction
Monitoring a Lock interface
Getting ready
How to do it...
How it works...
There's more...
See also
Monitoring a Phaser class
Getting ready
How to do it...
How it works...
See also
Monitoring an Executor framework
Getting ready
How to do it...
How it works...
See also
Monitoring a fork/join pool
Getting ready
How to do it...
How it works...
See also
Monitoring a stream
Getting ready
How to do it...
How it works...
See also
Writing effective log messages
Getting ready
How to do it...
How it works...
There's more...
See also
Analyzing concurrent code with FindBugs
Getting ready
How to do it...
How it works...
There's more...
See also
Configuring Eclipse for debugging concurrency code
Getting ready
How to do it...
How it works...
Configuring NetBeans for debugging concurrency code
Getting ready
How to do it...
How it works...
There's more...
See also
Testing concurrency code with MultithreadedTC
Getting ready
How to do it...
How it works...
There's more...
See also
Monitoring with JConsole
Getting ready
How to do it...
How it works...
There's more...
See also
Additional Information
Introduction
Processing results for Runnable objects in the Executor framework
Getting ready
How to do it...
How it works...
There's more...
See also
Processing uncontrolled exceptions in a ForkJoinPool class
How to do it...
How it works...
There's more...
See also
Using a blocking thread-safe queue for communicating with producers and consumers
Getting ready
How to do it...
How it works...
There's more...
See also
Monitoring a Thread class
Getting ready
How to do it...
How it works...
There's more...
See also
Monitoring a Semaphore class
Getting ready
How to do it...
How it works...
See also
Generating concurrent random numbers
Getting ready
How to do it...
How it works...
There's more...
See also
Concurrent Programming Design
Introduction
Using immutable objects when possible
Getting ready
How to do it...
How it works...
There's more...
See also
Avoiding deadlocks by ordering locks
How to do it...
How it works...
There's more...
See also
Using atomic variables instead of synchronization
Getting ready
How to do it...
How it works...
See also
Holding locks for as short time as possible
Getting ready
How to do it...
How it works...
See also
Delegating the management of threads to executors
Getting ready
How to do it...
How it works...
See also
Using concurrent data structures instead of programming yourself
There's more...
See also
Taking precautions using lazy initialization
Getting ready
How to do it...
How it works...
Using the fork/join framework instead of executors
Getting ready
How to do it...
How it works...
See also
Avoiding the use of blocking operations inside a lock
Getting ready
How to do it...
How it works...
See also
Avoiding the use of deprecated methods
Using executors instead of thread groups
See also
Using streams to process big data sets
Getting ready
How to do it...
How it works...
See also
Other tips and tricks
See also
When you work with a computer, you can do several things at once. You can listen to music while you edit a document in a word processor and read your e-mails. This can be done because your operating system allows the concurrency of tasks. Concurrent programming is about the elements and mechanisms a platform offers to have multiple tasks or programs running at once and communicating with each other, to exchange data or to synchronize with each other. Java is a concurrent platform, and it offers a lot of classes to execute concurrent tasks inside a Java program. With each version, Java increases the functionalities offered to programmers to facilitate the development of concurrent programs. This book covers the most important and useful mechanisms included in version 9 of the Java concurrency API, so you will be able to use them directly in your applications. The mechanisms are as follows:
Basic thread management
Thread synchronization mechanisms
Thread creation and management delegation with executors
Fork/Join framework to enhance the performance of your application
Parallel streams to process big sets of data in a parallel way, including the new Java 9 reactive streams
Data structures for concurrent programs
Adapting the default behavior of some concurrency classes to your needs
Testing Java concurrency applications
Chapter 1, Thread Management, teaches you how to make basic operations with threads. The creation, execution, and status management of threads are explained through basic examples.
Chapter 2, Basic Thread Synchronization, covers how to use low-level Java mechanisms to synchronize code. Locks and the synchronized keyword are explained in detail.
Chapter 3, Thread Synchronization Utilities, teaches how to use the high-level utilities of Java to manage the synchronization between threads in Java. It includes an explanation of how to use the Phaser class to synchronize tasks divided into phases.
Chapter 4, Thread Executors, explores the delegation of thread management to executors. They allow running, managing, and getting the results of concurrent tasks.
Chapter 5, Fork/Join Framework, covers the use of the Fork/Join framework. It’s a special kind of executor oriented to execute tasks that will be divided into smaller ones using the divide and conquer technique.
Chapter 6, Parallel and Reactive Streams, teaches you how to create streams and use all its intermediate and terminal operations to process big collections of data in a parallel and functional way. Streams were introduced in Java 8. Java 9 has included some new interfaces to implement reactive streams.
Chapter 7, Concurrent Collections, explains how to use some concurrent data structures provided by the Java language. These data structures must be used in concurrent programs to avoid the use of synchronized blocks of code in their implementation.
Chapter 8, Customizing Concurrency Classes, teaches you how to adapt some of the most useful classes of the Java concurrency API to your needs.
Chapter 9, Testing Concurrent Applications, covers how to obtain information about the status of some of the most useful structures of the Java 7 concurrency API. You will also learn how to use some free tools to debug concurrent applications, such as the Eclipse, NetBeans IDE, or FindBugs applications to detect possible bugs in your applications.
Chapter 10, Additional Information, explores the notions of synchronization, the executor, the Fork/Join framework, concurrent data structures, and the monitoring of concurrent objects, which were not included in the respective chapters.
Chapter 11, Concurrent Programming Design, provides some tips that every programmer should consider when they develop a concurrent application.
To follow this book, you need some basic knowledge of the Java programming language. You should know how to use an IDE, such as Eclipse or NetBeans, but this is not a necessary prerequisite.
If you are a Java developer interested in enhancing your knowledge of concurrent programming and multithreading further, as well as discovering the new concurrency features of Java 8 and Java 9, then the Java 9 Concurrency Cookbook is for you. You should already be comfortable with general Java development practices, and a basic grasp of threads would be an advantage.
In this book, you will find several headings that appear frequently (Getting ready, How to do it, How it works, There's more, and See also).
To give clear instructions on how to complete a recipe, we use these sections as follows:
This section tells you what to expect in the recipe, and describes how to set up any software or any preliminary settings required for the recipe.
This section contains the steps required to follow the recipe.
This section usually consists of a detailed explanation of what happened in the previous section.
This section consists of additional information about the recipe in order to make the reader more knowledgeable about the recipe.
This section provides helpful links to other useful information for the recipe.
In this book, you will find a number of text styles that distinguish between different kinds of information. Here are some examples of these styles and an explanation of their meaning.
Code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles are shown as follows: "The one that executes the main() method."
A block of code is set as follows:
Thread task=new PrimeGenerator(); task.start();
New terms and important words are shown in bold. Words that you see on the screen, for example, in menus or dialog boxes, appear in the text like this: "Create a new project by clicking on theNew Projectoption under theFilemenu"
Feedback from our readers is always welcome. Let us know what you think about this book-what you liked or disliked. Reader feedback is important for us as it helps us develop titles that you will really get the most out of.
To send us general feedback, simply e-mail [email protected], and mention the book's title in the subject of your message.
If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide at www.packtpub.com/authors .
Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase.
You can download the example code files for this book from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
You can download the code files by following these steps:
Log in or register to our website using your e-mail address and password.
Hover the mouse pointer on the
SUPPORT
tab at the top.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box.
Select the book for which you're looking to download the code files.
Choose from the drop-down menu where you purchased this book from.
Click on
Code Download
.
You can also download the code files by clicking on the Code Files button on the book's webpage at the Packt Publishing website. This page can be accessed by entering the book's name in the Search box. Please note that you need to be logged in to your Packt account.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR / 7-Zip for Windows
Zipeg / iZip / UnRarX for Mac
7-Zip / PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Java-9-Concurrency-Cookbook-Second-Edition. We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books-maybe a mistake in the text or the code-we would be grateful if you could report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions of this book. If you find any errata, please report them by visiting http://www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded to our website or added to any list of existing errata under the Errata section of that title.
To view the previously submitted errata, go to https://www.packtpub.com/books/content/support and enter the name of the book in the search field. The required information will appear under the Errata section.
Piracy of copyrighted material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works in any form on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy.
Please contact us at [email protected] with a link to the suspected pirated material.
We appreciate your help in protecting our authors and our ability to bring you valuable content.
If you have a problem with any aspect of this book, you can contact us at [email protected], and we will do our best to address the problem.
In this chapter, we will cover the following topics:
Creating, running, and setting the characteristics of a thread
Interrupting a thread
Controlling the interruption of a thread
Sleeping and resuming a thread
Waiting for the finalization of a thread
Creating and running a daemon thread
Processing uncontrolled exceptions in a thread
Using thread local variables
Grouping threads and processing uncontrolled exceptions in a group of threads
Creating threads through a factory
In the computer world, when we talk about concurrency, we refer to a series of independent and unrelated tasks that run simultaneously on a computer. This simultaneity can be real if the computer has more than one processor or a multi-core processor, or it can be apparent if the computer has only one core processor.
All modern operating systems allow the execution of concurrent tasks. You can read your e-mails while listening to music or reading news on a web page. We can say this is process-level concurrency. But inside a process, we can also have various simultaneous tasks. Concurrent tasks that run inside a process are called threads. Another concept related to concurrency is parallelism. There are different definitions and relations with the concurrency concept. Some authors talk about concurrency when you execute your application with multiple threads in a single-core processor. With this, you can see when your program execution is apparent. They talk about parallelism when you execute your application with multiple threads in a multi-core processor or in a computer with more than one processor, so this case is real as well. Other authors talk about concurrency when the threads of an application are executed without a predefined order, and they discuss parallelism when all these threads are executed in an ordered way.
This chapter presents a number of recipes that will show you how to perform basic operations with threads, using the Java 9 API. You will see how to create and run threads in a Java program, how to control their execution, process exceptions thrown by them, and how to group some threads to manipulate them as a unit.
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.
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.
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.
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.
The
Creating threads through a factory
recipe of this chapter
A Java program with more than one execution thread only finishes when the execution of all of its threads end (more specifically, when all its non-daemon threads end their execution or when one of the threads uses the System.exit() method). Sometimes, you may need to finish a thread because you want to terminate a program or when a user of the program wants to cancel the tasks that a thread object is doing.
Java provides an interruption mechanism that indicates to a thread that you want to finish it. One peculiarity of this mechanism is that thread objects have to check whether they have been interrupted or not, and they can decide whether they respond to the finalization request or not. A thread object can ignore it and continue with its execution.
In this recipe, we will develop a program that creates a thread and forces its finalization after 5 seconds, using the interruption mechanism.
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.
Follow these steps to implement the example:
Create a class called
PrimeGenerator
that extends the
Thread
class:
public class PrimeGenerator extends Thread{
Override the
run()
method including a loop that will run indefinitely. In this loop, process consecutive numbers beginning from one. For each number, calculate whether it's a prime number; if yes, as in this case, write it to the console:
@Override public void run() { long number=1L; while (true) { if (isPrime(number)) { System.out.printf("Number %d is Prime\n",number); }
After processing a number, check whether the thread has been interrupted by calling the
isInterrupted()
method. If this method returns
true
, the thread has been interrupted. In this case, we write a message in the console and end the execution of the thread:
if (isInterrupted()) { System.out.printf("The Prime Generator has been Interrupted"); return; } number++; } }
Implement the
isPrime()
method. You can get its code from the
Creating, running, and setting information of a thread
recipe of this chapter.
Now implement the main class of the example by implementing a class called
Main
and the
main()
method:
public class Main { public static void main(String[] args) {
Create and start an object of the
PrimeGenerator
class:
Thread task=new PrimeGenerator(); task.start();
Wait for 5 seconds and interrupt the
PrimeGenerator
thread:
try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } task.interrupt();
Then, write information related to the status of the interrupted thread. The output of this piece of code will depend on whether the thread ends its execution before or after:
System.out.printf("Main: Status of the Thread: %s\n", task.getState()); System.out.printf("Main: isInterrupted: %s\n", task.isInterrupted()); System.out.printf("Main: isAlive: %s\n", task.isAlive()); }
Run the example and see the results.
The following screenshot shows the result of the execution of the previous example. We can see how the PrimeGenerator thread writes the message and ends its execution when it detects that it has been interrupted. Refer to the following screenshot:
The Thread class has an attribute that stores a boolean value indicating whether the thread has been interrupted or not. When you call the interrupt() method of a thread, you set that attribute to true. The isInterrupted() method only returns the value of that attribute.
The main() method writes information about the status of the interrupted thread. In this case, as this code is executed before the thread has finished its execution, the status is RUNNABLE, the return value of the isInterrupted() method is true, and the return value of the isAlive() method is true as well. If the interrupted Thread finishes its execution before the execution of this block of code (you can, for example, sleep the main thread for a second), the methods isInterrupted() and isAlive() will return a false value.
The Thread class has another method to check whether a thread has been interrupted or not. It's the static method, interrupted(), that checks whether the current thread has been interrupted or not.
As mentioned earlier, a thread object can ignore its interruption, but this is not the expected behavior.
In the previous recipe, you learned how you can interrupt the execution of a thread and what you have to do to control this interruption in the thread object. The mechanism shown in the previous example can be used if the thread that can be interrupted is simple. But if the thread implements a complex algorithm divided into some methods or it has methods with recursive calls, we will need to use a better mechanism to control the interruption of the thread. Java provides the InterruptedException exception for this purpose. You can throw this exception when you detect the interruption of a thread and catch it in the run() method.
In this recipe, we will implement a task that will look for files with a determined name in a folder and in all its subfolders. This is to show how you can use the InterruptedException exception to control the interruption of a thread.
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.
The following screenshot shows the result of an execution of this example. You can see how the FileSearch object ends its execution when it detects that it has been interrupted.
In this example, we use Java exceptions to control the interruption of a thread. When you run the example, the program starts going through folders by checking whether they have the file or not. For example, if you enter in the \b\c\d folder, the program will have three recursive calls to the directoryProcess() method. When it detects that it has been interrupted, it throws an InterruptedException exception and continues the execution in the run() method, no matter how many recursive calls have been made.
The InterruptedException exception is thrown by some Java methods related to a concurrency API, such as sleep(). In this case, this exception is thrown if the thread is interrupted (with the interrupt() method) when it's sleeping.
The
Interrupting a thread
recipe of this chapter
Sometimes, you may be interested in pausing the execution of a thread during a determined period of time. For example, a thread in a program checks the sensor state once per minute. The rest of the time, it does nothing. During this time, the thread doesn't use any resources of the computer. After this period is over, the thread will be ready to continue with its execution when the operating system scheduler chooses it to be executed. You can use the sleep() method of the Thread class for this purpose. This method receives a long number as a parameter that indicates the number of milliseconds during which the thread will suspend its execution. After that time, the thread continues with its execution in the next instruction to the sleep() one when the JVM assigns it CPU time.
Another possibility is to use the sleep() method of an element of the TimeUnit enumeration. This method uses the sleep() method of the Thread class to put the current thread to sleep, but it receives the parameter in the unit that it represents and converts it into milliseconds.
In this recipe, we will develop a program that uses the sleep() method to write the actual date every second.
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.
When you run the example, you would see how the program writes a Date object per second and also the message indicating that the FileClock thread has been interrupted.
When you call the sleep() method, the thread leaves the CPU and stops its execution for a period of time. During this time, it's not consuming CPU time, so the CPU could be executing other tasks.
When the thread is sleeping and is interrupted, the method throws an InterruptedException exception immediately and doesn't wait until the sleeping time is finished.
The Java concurrency API has another method that makes a thread object leave the CPU. It's the yield() method, which indicates to the JVM that the thread object can leave the CPU for other tasks. The JVM does not guarantee that it will comply with this request. Normally, it's only used for debugging purposes.
In some situations, we will have to wait for the end of the execution of a thread (the run() method ends its execution). For example, we may have a program that will begin initializing the resources it needs before proceeding with the rest of the execution. We can run initialization tasks as threads and wait for their finalization before continuing with the rest of the program.
For this purpose, we can use the join() method of the Thread class. When we call this method using a thread object, it suspends the execution of the calling thread until the object that is called finishes its execution.
In this recipe, we will learn the use of this method with an initialization example.
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.
When you run this program, you would understand how both the thread objects start their execution. First, the DataSourcesLoader thread finishes its execution. Then, the NetworkConnectionsLoader class finishes its execution. At this moment, the main thread object continues its execution and writes the final message.
Java provides two additional forms of the join() method:
join (long milliseconds)
join (long milliseconds, long nanos)
In the first version of the join() method, instead of indefinitely waiting for the finalization of the thread called, the calling thread waits for the milliseconds specified as the parameter of the method. For example, if the object thread1 has thread2.join(1000), thread1 suspends its execution until one of these two conditions are met:
thread2
has finished its execution
1,000 milliseconds have passed
When one of these two conditions is true, the join() method returns. You can check the status of the thread to know whether the join() method was returned because it finished its execution or because the specified time had passed.
The second version of the join() method is similar to the first one, but it receives the number of milliseconds and nanoseconds as parameters.
Java has a special kind of thread called daemon thread. When daemon threads are the only threads running in a program, the JVM ends the program after finishing these threads.
With these characteristics, daemon threads are normally used as service providers for normal (also called user) threads running in the same program. They usually have an infinite loop that waits for the service request or performs the tasks of a thread. A typical example of these kinds of threads is the Java garbage collector.
In this recipe, we will learn how to create a daemon thread by developing an example with two threads: one user thread that would write events on a queue and a daemon thread that would clean the queue, removing the events that were generated more than 10 seconds ago.
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.
