Concurrency - Platform - Java 8 Pocket Guide (2014)

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