multithreading
play

Multithreading Basics thread state: runnable, blocked - PDF document

Multithreading Basics thread state: runnable, blocked Multithreading start, sleep, interrupt Synchronization race condition Horstmann ch.9 locks deadlock avoidance: await, notifyall Animation example:


  1. Multithreading • Basics – thread state: runnable, blocked Multithreading – start, sleep, interrupt • Synchronization – race condition Horstmann ch.9 – locks – deadlock avoidance: await, notifyall • Animation – example: mergesort Threads Running Threads • Define class that implements Runnable • Thread: program unit that is executed independently • Runnable has one method • Multiple threads run simultaneously void run() • Virtual machine executes each thread for short • Place thread action into run method time slice • Construct object of class • Thread scheduler activates, deactivates threads • Construct thread from that object • Illusion of threads running in parallel • Multiprocessor computers: threads actually run • Start thread in parallel Running Threads Thread Example • Run two threads in parallel public class MyRunnable implements Runnable { • Each thread prints 10 greetings public void run() { thread action } for (int i = 1; i <= 10; i++) { } System.out.println(i + ": " + greeting); Thread.sleep(100); ... } Runnable r = new MyRunnable(); • After each printout, sleep for 100 millisec Thread t = new Thread(r); • All threads should occasionally yield control t.start(); • sleep throws InterruptedException

  2. Class GreetingProducer Thread Example public class GreetingProducer implements Runnable { public GreetingProducer(String aGreeting) { greeting = aGreeting; } public void run() { try { for (int i = 1; i <= REPETITIONS; i++) { System.out.println(i + ": " + greeting); Thread.sleep(DELAY); } } catch (InterruptedException exception) { } } private String greeting; private static final int REPETITIONS = 10; private static final int DELAY = 100; } Class ThreadTest Thread Example public class ThreadTest { • Note: output not exactly 7: Hello, World! interleaved 7: Goodbye, World! public static void main(String[] args) { 8: Goodbye, World! Runnable r1 = new GreetingProducer("Hello, World!"); 8: Hello, World! 1: Hello, World! Runnable r2 = new GreetingProducer("Goodbye, World!"); 9: Goodbye, World! 1: Goodbye, World! Thread t1 = new Thread (r1); 9: Hello, World! 2: Hello, World! Thread t2 = new Thread (r2); 10: Goodbye, World! 2: Goodbye, World! t1. start (); 10: Hello, World! 3: Hello, World! t2. start (); 3: Goodbye, World! } 4: Hello, World! } 4: Goodbye, World! 5: Hello, World! 5: Goodbye, World! 6: Hello, World! 6: Goodbye, World! Starting Two Threads Thread States • Each thread has – thread state – priority • Thread states: – new (before start called) – runnable – blocked – dead (after run method exits)

  3. Thread States Blocked Thread State • Reasons for blocked state: – Sleeping – Waiting for I/O – Waiting to acquire lock (later) – Waiting for a condition (later) • Unblocks only if reason for block goes away Scheduling Threads Terminating Threads • Scheduler activates new thread if • Thread terminates when run exits – a thread has completed its time slice • Sometimes necessary to terminate – a thread has blocked itself running thread – a thread with higher priority has become runnable • Don't use deprecated stop method • Scheduler determines new thread to run • Interrupt thread by calling interrupt – looks only at runnable threads • Thread must cooperate and exit its run – picks one with max priority • Thread has chance to clean up Sensing Interruptions Sensing Interruptions • Thread could occasionally call public class MyRunnable implements Runnable { public void run() { Thread.currentThread().isInterrupted try { () while (...) { • sleep , wait throw InterruptedException do work when thread interrupted Thread.sleep(...); } • . . . and then the interruption status is cleared! } catch (InterruptedException e) {} clean up • More robust: Catch exception and react to } interruption } • Recommendation: Terminate run when sensing interruption

  4. Thread Synchronization Producer Thread int i = 1; • Use bounded queue from chapter 8 while (i <= greetingCount) { • Each producer thread inserts greetings if (! queue .isFull()) { queue .add(i + ": " + greeting); • Each consumer thread removes greetings i++; • Two producers, one consumer } Thread.sleep((int)(Math.random() * DELAY)); } all threads use same queue Consumer Thread int i = 1; • Expected Program • Why is Output while (i <= greetingCount) { Output Corrupted? if (! queue .isEmpty()) { • Sometimes program gets Object greeting = queue .remove(); 1: Hello, World! System.out.println(greeting); stuck and doesn't 1: Goodbye, World! i++; 2: Hello, World! complete } 3: Hello, World! • Can see problem better ... Thread.sleep((int)(Math.random() * DELAY)); when turning debugging 99: Goodbye, World! } on 100: Goodbye, World! queue.setDebug(true); add method in Queue Circular Array Implementation public void add(E newValue) { if (debug) System.out.print("add"); elements[tail] = newValue; if (debug) System.out.print("."); tail++; if (debug) System.out.print("."); size++; if (tail == elements.length) { • Efficient implementation of bounded queue if (debug) System.out.print("."); tail = 0; • Avoids inefficient shifting of elements } • Circular: head, tail indexes wrap around if (debug) System.out.println("head=" + head + ",tail=" + tail + ",size=" + size); • In circular array implementation, failure of remove } precondition corrupts queue!

  5. Race Condition remove method in Queue Scenario public E remove() { if (debug) System.out.print("removeFirst"); • First thread calls add and executes E r = (E) elements[head]; elements[tail] = newValue; if (debug) System.out.print("."); • First thread at end of time slice head++; • Second thread calls add and executes if (debug) System.out.print("."); elements[tail] = newValue; size--; tail++; if (head == elements.length) { • Second thread at end of time slice if (debug) System.out.print("."); • First thread executes head = 0; tail++; } if (debug) System.out.println("head=" + head + ",tail=" + tail + ",size=" + size); return r; } Locks Reentrant Locks aLock = new ReentrantLock(); • Thread can acquire lock . . . • When another thread tries to acquire same lock, aLock.lock(); it blocks try { • When first thread releases lock, other thread is protected code unblocked and tries again } • Two kinds of locks finally { – Objects of class implementing aLock.unlock(); java.util.concurrent.Lock interface type, usually } ReentrantLock – Locks that are built into every Java object Scenario with Locks Deadlocks • Assume body of add method protected by lock • Not enough to protect bodies of add , remove • if (!queue.isFull()) queue.add(...); • First thread calls add and acquires lock, then executes can still be interrupted elements[tail] = anObject; • Must move test inside add method • Second thread calls add and tries to acquire lock, but it public void add(E newValue) { is blocked queueLock.lock(); try { while ( queue is full ) • First thread executes wait for more space tail++; . . . • First thread completes add , releases lock } finally { queueLock.unlock(); } } • Second thread unblocked • Second thread acquires lock, starts executing protected • Problem: nobody else can call remove code

  6. Avoiding deadlocks Avoiding Deadlocks • Waiting thread is blocked • Use conditon object to manage "space available" condition • Condition object manages set of threads that wait for the condition to change private Lock queueLock = new ReentrantLock(); private Condition spaceAvailableCondition = • To unblock, another thread must call signalAll on the same condition queueLock.newCondition(); object • Call when state changes • Call await when condition is not fulfilled: public E remove() { public void add(E newValue) { . . . . . . E r = (E) elements[head]; while (size == elements.length) . . . spaceAvailableCondition.await(); spaceAvailableCondition.signalAll(); . . . // Unblock waiting threads } return r; } • All waiting threads removed from wait set, unblocked Object Locks Object Locks • Each object has a lock • Each implicit lock has one associated (anonymous) condition object • Calling a synchronized method acquires lock of implicit parameter • Object.wait blocks current thread and adds it to wait set • Leaving the synchronized method releases lock • Object.notifyAll unblocks waiting threads • Easier than explicit Lock objects public synchronized void add(E newValue public class BoundedQueue<E> { throws InterruptedException { public synchronized void add(E newValue) { ... } while (size == elements.length) wait(); elements[tail] = anObject; public synchronized E remove() { ... } . . . notifyAll(); ... // notifies threads waiting to remove elements } } Visualizing Locks Algorithm Animation • Use thread to make progress in algorithm • Object = phone booth • Display algorithm state • Thread = person • Example: Animate MergeSorter (similar to java.util.Arrays.sort ) • Pause inside compare method • Locked object = closed booth • Pass custom comparator • Blocked thread = person waiting for booth to open Comparator<Double> comp = new Comparator<Double>() { public int compare(Double d1, Double d2) { draw current state pause thread return d1.compareTo(d2); } };

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend