Java 8 Pocket Guide (2014)
Part II. Platform
Chapter 14. Concurrency
Threads in Java allow the use of multiple processors or multiple cores in one processor more efficiently. On a single processor, threads provide for concurrent operations such as overlapping I/O with processing.
Java supports multithreaded programming features with the Thread class and the Runnable interface.
Creating Threads
Threads can be created two ways, either by extending java.lang.Thread or by implementing java.lang.Runnable.
Extending the Thread Class
Extending the Thread class and overriding the run() method can create a threadable class. This is an easy way to start a thread:
class Comet extends Thread {
public void run() {
System.out.println("Orbiting");
orbit();
}
}
Comet halley = new Comet();
hally.run();
Remember that only one superclass can be extended, so a class that extends Thread cannot extend any other superclass.
Implementing the Runnable Interface
Implementing the Runnable functional interface and defining its run() method can also create a threadable class.
class Asteroid implements Runnable {
public void run() {
System.out.println("Orbiting");
orbit();
}
}
Asteroid majaAsteroid = new Asteroid();
Thread majaThread = new Thread(majaAsteroid);
majaThread.run();
A single runnable instance can be passed to multiple thread objects. Each thread performs the same task, as shown here after the use of a Lambda Expression:
Runnable asteroid = () -> {
System.out.println("Orbiting");
orbit();
};
Thread asteroidThread1 = new Thread(asteroid);
Thread asteroidThread2 = new Thread(asteroid);
asteroidThread1.run();
asteroidThread2.run();
Thread States
Enumeration Thread.state provides six thread states, as depicted in Table 14-1.
Table 14-1. Thread states
Thread state |
Description |
NEW |
A thread that is created but not started |
RUNNABLE |
A thread that is available to run |
BLOCKED |
An “alive” thread that is blocked waiting for a monitor lock |
WAITING |
An “alive” thread that calls its own wait() or join() while waiting on another thread |
TIMED_WAITING |
An “alive” thread that is waiting on another thread for a specified period of time; sleeping |
TERMINATED |
A thread that has completed |
Thread Priorities
The valid range of priority values is typically 1 through 10, with a default value of 5. Thread priorities are one of the least portable aspects of Java, as their range and default values can vary among Java Virtual Machines (JVMs). Using MIN_PRIORITY, NORM_PRIORITY, andMAX_PRIORITY can retrieve priorities.
System.out.print(Thread.MAX_PRIORITY);
Lower priority threads yield to higher priority threads.
Common Methods
Table 14-2 contains common methods used for threads from the Thread class.
Table 14-2. Thread methods
Method |
Description |
getPriority() |
Returns the thread’s priority |
getState() |
Returns the thread’s state |
interrupt() |
Interrupts the thread |
isAlive() |
Returns the thread’s alive status |
isInterrupted() |
Checks for interruption of the thread |
join() |
Causes the thread that invokes this method to wait for the thread that this object represents to finish |
setPriority(int) |
Sets the thread’s priority |
start() |
Places the thread into a runnable state |
Table 14-3 contains common methods used for threads from the Object class.
Table 14-3. Methods from the Object class used for threads
Method |
Description |
notify() |
Tells a thread to wake up and run |
notifyAll() |
Tells all threads that are waiting on a thread or resource to wake up, and then the scheduler will select one of the threads to run |
wait() |
Pauses a thread in a wait state until another thread calls notify() or notifyAll() |
TIP
Calls to wait() and notify() throw an InterruptedException if called on a thread that has its interrupted flag set to true.
Table 14-4 contains common static methods used for threads from the Thread class (i.e., Thread.sleep(1000)).
Table 14-4. Static thread methods
Method |
Description |
activeCount() |
Returns number of threads in the current thread’s group |
currentThread() |
Returns reference to the currently running thread |
interrupted() |
Checks for interruption of the currently running thread |
sleep(long) |
Blocks the currently running thread for parameter number of milliseconds |
yield() |
Pauses the current thread to allow other threads to run |
Synchronization
The synchronized keyword provides a means to apply locks to blocks and methods. Locks should be applied to blocks and methods that access critically shared resources. These monitor locks begin and end with opening and closing braces. Following are some examples of synchronized blocks and methods.
Object instance t with a synchronized lock:
synchronized (t) {
// Block body
}
Object instance this with a synchronized lock:
synchronized (this) {
// Block body
}
Method raise() with a synchronized lock:
// Equivalent code segment 1
synchronized void raise() {
// Method Body
}
// Equivalent code segment 2
void raise() {
synchronized (this) {
// Method body
}
}
Static method calibrate() with a synchronized lock:
class Telescope {
synchronized static void calibrate() {
// Method body
}
}
TIP
A lock is also known as a monitor or mutex (mutually exclusive lock).
The concurrent utilities provide additional means to apply and manage concurrency.
Concurrent Utilities
Java 2 SE 5.0 introduced utility classes for concurrent programming. These utilities reside in the java.util.concurrent package, and they include executors, concurrent collections, synchronizers, and timing utilities.
Executors
The class ThreadPoolExecutor as well as its subclass ScheduledThreadPoolExecutor implement the Executor interface to provide configurable, flexible thread pools. Thread pools allow server components to take advantage of the reusability of threads.
The class Executors provides factory (object creator) methods and utility methods. Of them, the following are supplied to create thread pools:
newCachedThreadPool()
Creates an unbounded thread pool that automatically reuses threads
newFixedThreadPool(int nThreads)
Creates a fixed-size thread pool that automatically reuses threads off a shared unbounded queue
newScheduledThreadPool(int corePoolSize)
Creates a thread pool that can have commands scheduled to run periodically or on a specified delay
newSingleThreadExecutor()
Creates a single-threaded executor that operates off an unbounded queue
newSingleThreadScheduledExecutor()
Creates a single-threaded executor that can have commands scheduled to run periodically or by a specified delay
The following example demonstrates usage of the newFixedThreadPool factory method:
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class ThreadPoolExample {
public static void main() {
// Create tasks
// (from 'class RTask implements Runnable')
RTask t1 = new RTask("thread1");
RTask t2 = new RTask("thread2");
// Create thread manager
ExecutorService threadExecutor =
Executors.newFixedThreadPool(2);
// Make threads runnable
threadExecutor.execute(t1);
threadExecutor.execute(t2);
// Shut down threads
threadExecutor.shutdown();
}
}
Concurrent Collections
Even though collection types can be synchronized, it is best to use concurrent thread-safe classes that perform equivalent functionality, as represented in Table 14-5.
Table 14-5. Collections and their thread-safe equivalents
Collection class |
Thread-safe equivalent |
HashMap |
ConcurrentHashMap |
TreeMap |
ConcurrentSkipListMap |
TreeSet |
ConcurrentSkipListSet |
Map subtypes |
ConcurrentMap |
List subtypes |
CopyOnWriteArrayList |
Set subtypes |
CopyOnWriteArraySet |
PriorityQueue |
PriorityBlockingQueue |
Deque |
BlockingDeque |
Queue |
BlockingQueue |
Synchronizers
Synchronizers are special-purpose synchronization tools. Available synchronizers are listed in Table 14-6.
Table 14-6. Synchronizers
Synchronizer |
Description |
Semaphore |
Maintains a set of permits |
CountDownLatch |
Implements waits against sets of operations being performed |
CyclicBarrer |
Implements waits against common barrier points |
Exchanger |
Implements a synchronization point where threads can exchange elements |
Timing Utility
The TimeUnit enumeration is commonly used to inform time-based methods how a given timing parameter should be evaluated, as shown in the following example. Available TimeUnit enum constants are listed in Table 14-7.
// tyrLock (long time, TimeUnit unit)
if (lock.tryLock(15L, TimeUnit.DAYS)) {...} //15 days
Table 14-7. TimeUnit constants
Constants |
Unit def. |
Unit (sec) |
Abbreviation |
NANOSECONDS |
1/1000 µs |
.000000001 |
ns |
MICROSECONDS |
1/1000 ms |
.000001 |
µs |
MILLISECONDS |
1/1000 sec |
.001 |
ms |
SECONDS |
sec |
1 |
sec |
MINUTES |
60 sec |
60 |
min |
HOURS |
60 min |
3600 |
hr |
DAYS |
24 hr |
86400 |
d |