Threads Java Threads "The real payoff of concurrent execution arises not from the fact that applications can be speeded up by artificially introducing concurrency, but from the fact that the real world functions by the execution of concurrent activities.” – P. Wegner ©SoftMoore Consulting
Importance of Concurrent Programming Facilities Threads Importance of Concurrent Programming Facilities Concurrent execution (on multiprocessing hardware) can improve program performance. Many applications are modeled more naturally as systems of concurrently executing threads. A concurrent program preserves the structure of a concurrent problem. Concurrent programming facilities enhance the programmer’s ability to “invent” concurrent solutions. ©SoftMoore Consulting
Threads Threads A thread (a.k.a., a lightweight process) is a single sequential flow of control within a Java program. A thread may operate in parallel with other threads. Concurrency may be real (if the underlying computer has more than one processor) or simulated (via interleaved execution on a single processor). Conceptually it is best to think of each thread as having its own personal processor. Java provides support for concurrency at the class level, not at the statement level. ©SoftMoore Consulting
Concurrency Utilities in Java 5 Version 5 of Java added three new thread-related packages: java.util.concurrent java.util.concurrent.atomic java.util.concurrent.locks The classes and interfaces in these packages provided high-quality, thread-safe building blocks for developing concurrent classes and applications. thread pools − task synchronization utilities thread-safe collections − a task scheduling framework semaphores − atomic variables locks − condition objects ©SoftMoore Consulting
Creating Threads Two ways to create a thread: Create a class that implements the Runnable interface. public interface Runnable { void run(); } Extend the Thread class and override its run() method. If your class must subclass some other class (e.g., Applet), you will need to use the first alternative. Implementing the Runnable interface is the preferred way to create a thread. ©SoftMoore Consulting
Creating a Thread by Implementing the Runnable Interface Threads Creating a Thread by Implementing the Runnable Interface Create a class that implements the Runnable interface, and place the code for the thread in the run() method. public class SimpleRunnable extends SomeClass implements Runnable { public SimpleRunnable() { ... } @Override public void run() { ... } } ©SoftMoore Consulting
Creating a Thread by Implementing the Runnable Interface (continued) Threads Creating a Thread by Implementing the Runnable Interface (continued) Construct an object of the class. Runnable r = new SimpleRunnable(); Construct a Thread object from the Runnable object. Thread t = new Thread(r); Start the thread. t.start(); ©SoftMoore Consulting
Creating a Thread by Implementing the Runnable Interface (continued) Threads Creating a Thread by Implementing the Runnable Interface (continued) Alternate steps 3 and 4 (added in Java 5) Obtain an Executor object (e.g., from java.util.concurrent.ExecutorService). Executor e = ...; // several choices in package // java.util.concurrent Execute the thread. e.execute(r); ©SoftMoore Consulting
Creating a Thread by Extending the Thread Class Threads Creating a Thread by Extending the Thread Class public class SimpleThread extends Thread { public SimpleThread() ... } @Override public void run() // elsewhere (e.g., in another class) Thread t = new SimpleThread(); t.start(); This approach is no longer recommended. ©SoftMoore Consulting
Key Constructors and Methods in Class Thread Threads Key Constructors and Methods in Class Thread Constructors public Thread() public Thread(Runnable target) Methods public void run() // called by JVM public void start() public static void sleep(long milliseconds) public static void yield() // use to prevent "starvation" public boolean isAlive() public void join() // waits for this thread to die public void join(long milliseconds) public static Thread currentThread() ©SoftMoore Consulting
Threads Deprecated Methods public void stop() public void suspend() public void resume() Note: These methods are inherently unsafe and have been deprecated. ©SoftMoore Consulting
Method sleep() in Class Thread Threads Method sleep() in Class Thread The method sleep() causes the currently executing thread to sleep (temporarily cease execution) for the specified time, subject to limitations of the underlying operating system. Two versions public static void sleep(long millis) … public static void sleep(long milis, long nanos) … A call to sleep() with a value of 0 can be used to indicate that the thread is willing to relinquish the processor to other waiting threads. Calling method yield() is preferable to calling sleep(0) if a thread is willing to allow other waiting threads to execute. ©SoftMoore Consulting
Method Thread.sleep() (continued) Constants can be used to improve readability private static final long MILLISECONDS = 1; private static final long SECONDS = 1000*MILLISECONDS; private static final long MINUTES = 60*SECONDS; ... Thread.sleep(50*MILLISECONDS); Thead.sleep(2*MINUTES + 30*SECONDS); ©SoftMoore Consulting
Example: Simple Thread Threads Example: Simple Thread public class SimpleRunnable implements Runnable { private String message; public SimpleRunnable(String message) { this.message = message; } ©SoftMoore Consulting
Example: Simple Thread (continued) Threads Example: Simple Thread (continued) @Override public void run() { for (int i = 0; i < 10; ++i) { System.out.println(i + " " + message); try { Thread.sleep((int)(Math.random()*100)); } catch (InterruptedException e) { ... } } } } ©SoftMoore Consulting
Example: Simple Thread (continued) Threads Example: Simple Thread (continued) public class SimpleRunnableTest { public static void main (String[] args) Runnable r1 = new SimpleRunnable("Hello"); Runnable r2 = new SimpleRunnable("World"); Thread t1 = new Thread(r1); Thread t2 = new Thread(r2); t1.start(); t2.start(); } ©SoftMoore Consulting
Thread States A thread can be in one of the following states: NEW − not yet started RUNNABLE − ready to run BLOCKED − waiting to acquire a lock WAITING − waiting indefinitely for another thread to perform a particular action TIMED_WAITING − waiting for another thread to perform an action for up to a specified waiting time TERMINATED − finished executing; e.g., run method has completed or uncaught exception has been raised method isAlive() returns true ©SoftMoore Consulting
Thread States Diagram BLOCKED NEW RUNNABLE WAITING Ready Running TIMED IO complete or lock acquired NEW new() block on IO or wait for lock/synchronized block start() RUNNABLE WAITING processor available wait(), join(), park() Ready Running notify(), notifyAll() yield finished executing TIMED WAITING sleep(time), wait(time), join(time), park(time) TERMINATED time elapsed ©SoftMoore Consulting
Timed Loops – With Cumulative Drift Threads Timed Loops – With Cumulative Drift while (true) { try … // actions Thread.sleep(30*SECONDS); } catch (InterruptedException ex) … Time to complete an iteration of the loop includes time to perform the actions. ©SoftMoore Consulting
Timed Loops – Avoiding Drift Threads Timed Loops – Avoiding Drift private static final long INTERVAL = 30*SECONDS; private long nextTime = System.currentTimeMillis(); ... while (true) { try ... // actions nextTime = nextTime + INTERVAL; Thread.sleep(nextTime - System.currentTimeMillis()); } catch (InterruptedException ex) … ©SoftMoore Consulting
Example: Monitoring Water Temperature Threads Example: Monitoring Water Temperature public class WaterTempMonitor extends Thread { private static final long INTERVAL = 5*SECONDS; ... @Override public void run() long nextTime = System. currentTimeMillis(); while (true) if (getWaterTemperature() > MAX_TEMPERATURE) activateAlarm(); nextTime = nextTime + INTERVAL; Thread.sleep(nextTime – System.currentTimeMillis()); } ©SoftMoore Consulting
Threads Example: Monitoring Water Temperature (Using Java 8 Time-Related Classes) public class WaterTempMonitor extends Thread { private static final long INTERVAL = 5; // seconds ... @Override public void run() private Instant nextTime = Instant.now(); while (true) if (getWaterTemperature() > MAX_TEMPERATURE) activateAlarm(): nextTime = nextTime.plusSeconds(INTERVAL); Duration dur = Duration.between(Instant.now(), nextTime); Thread.sleep(dur.toMillis()); } ©SoftMoore Consulting
Thread Names Threads have names Constructors and methods no real semantics used for identification and debugging. Constructors and methods public Thread(String name) public Thread(Runnable target, String name) public void setName(String name) public String getName() Default name: “Thread-”<unique number> Name is returned by the toString() method ©SoftMoore Consulting
Threads Thread Priority Each thread has a priority. A higher value indicates a higher degree of urgency. Constants in class Thread public static final int MAX_PRIORITY // defined as 10 public static final int MIN_PRIORITY // defined as 1 public static final int NORM_PRIORITY // default (5) Methods public void setPriority(int newPriority) public int getPriority() Thread priorities are mapped to the priority levels of the host platform, which may have more or fewer priority levels; e.g., Windows has seven levels. ©SoftMoore Consulting
Thread Priority (continued) Threads Thread Priority (continued) If two threads are in the ready state, the one with the highest priority will be selected to run. Caution: Improper use of thread priorities can result in “starvation” of threads with lower priorities. ©SoftMoore Consulting
Threads Thread Interaction Threads need to interact with each other for several reasons: Information Exchange Activity Synchronization to coordinate the activities of parallel threads executing asynchronously Mutual Exclusion to get exclusive access to a shared resource ©SoftMoore Consulting
Protecting Shared Resources Threads Protecting Shared Resources Whenever several threads have access to a shared resource, we must maintain the integrity of the operations and data. Mutual exclusion means that only one thread of control can operate upon that resource at a time – multiple threads of control are serialized. In order to prevent simultaneous updates by different threads, we must provide exclusive access to a shared resource. “The basic concurrent programming problem is mutual exclusion.” – M. Ben-Ari ©SoftMoore Consulting
The Need for Mutual Exclusion public void transfer(Account from, Account to, Double amount) { from.debit(amount); to.credit(amount); } Recall that each Java statement is translated into multiple JVM instructions. Consider what could happen if two threads are simultaneously trying to update the same account, and the first thread is preempted before completing the transfer() method. ©SoftMoore Consulting
Synchronization Locks Synchronization is based on locks. Threads Synchronization Locks Since version 1.0, every object in Java has an intrinsic lock. Java 5.0 added additional lock classes such as ReentrantLock and ReadWriteLock. Synchronization is based on locks. Synchronized code is atomic – only one thread at a time can execute the synchronized code. ©SoftMoore Consulting
Synchronization (continued) Threads Synchronization (continued) Synchronized methods public synchronized void someMethod() { ... // statements } Synchronized block of code ... // statements synchronized(someObject) ... // statements } Note: someObject is often this or an object created specifically for use as a lock. ©SoftMoore Consulting
Waiting and Notification Threads Waiting and Notification It is possible for a thread to “wait” for some condition to occur. Another thread can then “notify” the waiting thread that the condition has occurred. Primitive methods inherited from class Object wait() wait(long timeout) notify() notifyAll() ©SoftMoore Consulting
Example: Waiting and Notification Threads Example: Waiting and Notification public synchronized void getResource(int numberToGet) { while (true) if (resourceCount > numberToGet) resourceCount -= numberToGet; break; } try wait(); catch (Exception e) ©SoftMoore Consulting
Example: Waiting and Notification (continued) Threads Example: Waiting and Notification (continued) public synchronized void freeResource(int numberToFree) { resourceCount += numberToFree; notifyAll(); } ©SoftMoore Consulting
Using Waiting and Notification Threads Using Waiting and Notification Must be used in conjunction with synchronization The thread calling methods wait(), notify(), etc. must hold locks for the object for which they are waiting or notifying. The wait() method releases the lock prior to waiting and reacquires it prior to returning from the wait() method. Note: Methods wait(), notify(), etc. have been part of Java since the 1.0 release, but this functionality has essentially been replaced by explicit locks and methods await(), signal(), signalAll(), etc. ©SoftMoore Consulting
Threads Race Conditions A race condition is a set of circumstances in which the relative speeds of two threads can influence the result of program execution. It can occur when two concurrent threads operate on a shared resource in overlapping time intervals. Example thread1 if (!stack.isEmpty()) x = stack.pop(); thread2 if (!stack.isEmpty()) x = stack.pop(); time ©SoftMoore Consulting
Race Conditions (continued) Threads Race Conditions (continued) Race conditions typically have irreproducible results, making the construction of reliable concurrent systems difficult. ©SoftMoore Consulting
Threads Deadlock Deadlock is the situation in which one or more threads become permanently blocked waiting for resources that will never become available. Example thread1 synchronize(resource1) { synchronize(resource2) { ... } } thread2 synchronize(resource2) { synchronize(resource1) { ... } } time ©SoftMoore Consulting
Deadlock (continued) Conditions for deadlock Reasons for deadlock Threads Deadlock (continued) Conditions for deadlock mutual exclusion partial resource allocation nonpreemptive scheduling circular waiting Reasons for deadlock poor program design occurrence of unanticipated events ©SoftMoore Consulting
Threads Deadlock Avoidance Ensure that the four conditions necessary for deadlock are not satisfied at the same time Strategies grant permission for using both (all) resources simultaneously, instead of one at a time require a thread to give up its resources temporarily order the resources; e.g., each thread must get permission for resource1 first and then for resource2, to avoid the circular-wait problem ©SoftMoore Consulting
Threads Thread Interruption It is possible for one thread to immediately signal another thread. analogy with a call on your cell phone An interrupt signals the thread to stop doing what it is currently doing and do something else. Associated methods void interrupt() Interrupts this thread. static boolean interrupted() Tests whether the current thread has been interrupted. ©SoftMoore Consulting
Effect of Interrupting a Thread Threads Effect of Interrupting a Thread If the interrupted thread is executing a wait(), sleep(), or join() method, that method will throw an InterruptedException. The interrupted thread moves to an unblocked state. Otherwise, a flag is set that can be tested via the interrupted() method. Many methods that throw InterruptedException (e.g., sleep()) are designed to cancel their current operation and return immediately when an interrupt is received. ©SoftMoore Consulting
Terminating a Thread The normal way for a thread to terminate is for the run() method to return after it has finished. To “force” termination of a running thread, call its interrupt() method, which will set a boolean flag in the thread indicating that it should terminate. t.interrupt(); A thread can check to see if the flag has been set by calling the static method interrupted(), which returns the value of the boolean flag. ©SoftMoore Consulting
Terminating a Thread (continued) Calling the interrupt() method allows the interrupted thread to release any resources it is currently using and perform other required cleanup before terminating; i.e., the thread is in charge of terminating itself. Class Thread also contains a method stop() that will immediately terminate a thread, but this method has been shown to be inherently unsafe and is now deprecated. Do not call method stop() on a thread. ©SoftMoore Consulting
Threads Daemon Threads A daemon thread is a thread whose purpose is to serve “user” threads. During thread scheduling, if only daemon threads remain, the program will terminate. Example: the garbage collector thread Relevant methods void setDaemon(boolean on) boolean isDaemon() The setDaemon() method must be called before the thread has been started. ©SoftMoore Consulting
Threads Explicit Locks A lock is a tool for controlling access to a shared resource by multiple threads. Commonly, a lock provides exclusive access only one thread at a time can acquire the lock, and all access to the shared resource requires that the lock be acquired first Some locks may allow concurrent access to a shared resource, such as the read lock of a ReadWriteLock. Explicit locks are provided in package java.util.concurrent.locks ©SoftMoore Consulting
The Lock Interface package java.util.concurrent.locks; Threads The Lock Interface package java.util.concurrent.locks; public interface Lock { public void lock(); public void lockInterruptibly(); public Condition newCondition(); public boolean tryLock(); public boolean tryLock(long time, TimeUnit unit); public void unlock(); } ©SoftMoore Consulting
The ReadWriteLock Interface Threads The ReadWriteLock Interface package java.util.concurrent.locks; public interface ReadWriteLock { public Lock readLock(); public Lock writeLock(); } A ReadWriteLock maintains a pair of associated locks one for read-only operations one for writing Permits multiple concurrent readers but only one writer. ©SoftMoore Consulting
Lock Implementations ReentrantLock implements Lock Threads Lock Implementations ReentrantLock implements Lock thread can repeatedly acquire a lock that it already owns (can call another method that uses the same lock) must call unlock() for every call to lock() lock keeps track of nested calls to the lock() method ReentrantReadWriteLock implements ReadWriteLock reentrant (see above) If readers are active and a writer enters the lock, then no subsequent readers will be granted the read lock until after that writer has acquired and released the write lock. supports an optional fairness policy, where threads contend for entry using an approximately arrival-order policy ©SoftMoore Consulting
Threads Using Explicit Locks An explicit lock is more flexible than using synchronized blocks and methods since locks can span a few statements in a method or calls to multiple methods. Must ensure that the lock is released Lock l = ...; // usually a ReentrantLock l.lock(); try { // critical section // access the resource protected by this lock } finally l.unlock(); ©SoftMoore Consulting
Package java.util.concurrent.atomic The package java.util.concurrent.atomic contains several classes that support lock-free thread-safe programming on single variables. AtomicBoolean − AtomicInteger AtomicIntegerArray − AtomicLong LongAdder − ... Methods calls on instances of these classes are atomic; i.e., the calls are thread-safe without using the synchronized keyword or locks. Internally, the atomic classes use atomic instructions directly supported by most modern CPUs, so they are usually much faster than synchronizing via locks. ©SoftMoore Consulting
Threads Condition Objects A lock object can have one or more associated condition objects. Lock l = new ReentrantLock(); Condition needResource = lock.newCondition(); If a thread has acquired a lock but then discovers that it can’t continue until a certain condition is met, it can indicate that it is willing to wait on that condition using one of several Condition.await methods. When a thread performs an action that satisfies a condition, it can notify waiting threads that the condition has been met by calling one of two Condition.signal methods. ©SoftMoore Consulting
Condition Await Methods Threads Condition Await Methods Method Description await() Wait until signaled or interrupted await(long, TimeUnit) Wait until signaled or interrupted, or the specified waiting time elapses awaitNanos(long) awaitUninterruptibly() Wait until it is signaled awaitUntil(Date) Wait until signaled or interrupted, or the specified deadline elapses ©SoftMoore Consulting
Condition Signal Methods Threads Condition Signal Methods Method Description signal() Wakes up one waiting thread. signalAll() Wakes up all waiting threads. Usually you should call signallAll(). It is slightly less efficient, but it is also less prone to deadlock. ©SoftMoore Consulting
Example: Condition Objects Threads Example: Condition Objects public class BoundedBuffer { Lock lock = new ReentrantLock(); Condition notFull = lock.newCondition(); Condition notEmpty = lock.newCondition(); public void put(Object x) throws InterruptedException lock.lock(); try while (count == items.length) notFull.await(); … // add x to the buffer notEmpty.signalAll(); } finally lock.unlock(); ©SoftMoore Consulting
Example: Condition Objects (continued) Threads Example: Condition Objects (continued) public Object get() throws InterruptedException { lock.lock(); try while (count == 0) notEmpty.await(); … // remove x from the buffer notFull.signalAll(); return x; } finally lock.unlock(); Note: Class ArrayBlockingQueue provides the functionality illustrated by this example. ©SoftMoore Consulting
Blocked by a Lock versus Blocked Awaiting a Condition Threads Blocked by a Lock versus Blocked Awaiting a Condition There is a difference between a thread that is blocked while waiting to acquire a lock and a thread that has called await(). When a thread calls await(), it enters a wait set for that condition. The thread is not unblocked when the lock is available. Instead, it stays blocked until another thread calls signal() or signalAll() on the same condition. ©SoftMoore Consulting
Thread Groups A ThreadGroup class manages a group of related threads. ThreadGroup group = new ThreadGroup(groupName); Thread t = new Thread(group, r); A thread group can contain not only threads but also other thread groups (similar to directories). The top most thread group is named “main”. Class ThreadGroup contains several methods that can be used to manage the contained threads and groups; e.g., it is possible to set the name for the group, to get an array of all threads in the group, and to set the priority for the entire group. ©SoftMoore Consulting
Concurrent Collections (in java.util.concurrent) Threads Concurrent Collections (in java.util.concurrent) Interfaces BlockingDeque BlockingQueue ConcurrentMap Implementations (classes) ArrayBlockingQueue ConcurrentHashMap ConcurrentLinkedQueue CopyOnWriteArrayList CopyOnWriteArraySet LinkedBlockingDeque LinkedBlockingQueue PriorityBlockingQueue ©SoftMoore Consulting
Buffered Communication Threads Buffered Communication Buffering can be used to smooth out variations in speeds of two communicating threads. With a large enough buffer, the actual data flow will approximate the average data flow. Java provides blocking queues for buffering communication between threads. A blocking queue causes a thread to block when trying to add an element to a full queue when trying to remove an element from an empty queue Often one thread writes to the queue while another thread reads from the queue. ©SoftMoore Consulting
Interface BlockingQueue Threads Interface BlockingQueue Three categories of methods based on response to failure (e.g., attempting to add an element to a full queue or remove an element from an empty queue) Methods that throw an exception add() remove() element() Methods that return a value indicating failure offer() poll() peek() Methods that block put() take() Implemented by several classes ArrayBlockingQueue – PriorityBlockingQueue LinkedBlockingQueue – etc. ©SoftMoore Consulting
Asynchronous Communication Threads Asynchronous Communication Asynchronous communication between two threads can be achieved by defining a third thread as a mailbox. Example public class MailBox { public synchronized void write(String message) {...} public synchronized String read() {...} ... // other implementation details } Mailboxes could be created dynamically as needed. A blocking queue could be used to implement the mailbox. thread 1 mailbox thread 2 ©SoftMoore Consulting
Thread Safety (Brian Goetz) A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code. Writing thread-safe code is about managing access to shared, mutable state, where an object’s state is its data. Thread-safe classes encapsulate any needed synchronization so that clients need not provide their own. ©SoftMoore Consulting
Threads More on Thread Safety Stateless objects and immutable objects are always thread-safe. Parameters and local variables (declared within a method) are stored on the run-time stack, and each thread has its on stack. A method that uses only local variables or parameters is always thread safe as long as it doesn’t use parameters to modify mutable objects. An object that is accessed by only one thread need not be thread-safe. simpler, better performance but … are you sure that it never will be accessed by multiple threads? ©SoftMoore Consulting
Levels of Thread Safety (Joshua Bloch) Immutable Unconditionally thread-safe class has sufficient internal synchronization Conditionally thread-safe some methods require external synchronization Not thread-safe require external synchronization examples: ArrayList and HashMap Thread-hostile usually not-intentional example: System.runFinalizersOnExit() method ©SoftMoore Consulting
Guidelines for Effective Java (Joshua Bloch) Threads Guidelines for Effective Java (Joshua Bloch) Synchronize access to shared mutable data Synchronization is required for reliable communication between threads as well as for mutual exclusion. Avoid excessive synchronization As a rule, do as little work as possible inside synchronized regions. Prefer executors to tasks and threads (More on this when we study networking.) Prefer concurrency utilities to wait and notify e.g., use ConcurrentHashMap in preference to Collections.synchronizedMap or Hashtable Document thread safety ©SoftMoore Consulting
Recommendations (Horstmann and Cornell) Threads Recommendations (Horstmann and Cornell) It is best to use neither Lock/Condition nor the synchronized keyword. In many situations you can use one of the mechanisms of the package java.util.concurrent (e.g., BlockingQueue) that do all the locking for you. If the synchronized keyword works for your situation, then use it. less code to write less room for error Use Lock/Condition if you specifically need the additional power that these constructs provide. ©SoftMoore Consulting