Multithreading Horstmann ch.9 Multithreading Threads Thread - - PDF document
Multithreading Horstmann ch.9 Multithreading Threads Thread - - PDF document
Multithreading Horstmann ch.9 Multithreading Threads Thread states Thread interruption Race condition Lock Built-in lock java.util.concurrent library Animation example Single vs. Multiple Threads Finish
Multithreading
- Threads
- Thread states
- Thread interruption
- Race condition
- Lock
- Built-in lock
- java.util.concurrent library
- Animation example
Single vs. Multiple Threads
- Finish each line of
bullets before starting new line
- Allow simultaneous
drawing of several lines
ThreadTester1 ThreadTester2
Single vs. Multiple Threads
Using single thread:
in method actionPerformed: ... for (int i=0; i<10; i++) { ”draw single bullet”; Thread.sleep(500); } ...
Running Threads
public class MyRunnable implements Runnable { public void run() { thread action } } ... Runnable r = new MyRunnable(); Thread t = new Thread(r); t.start();
Specify action Construct thread from Runnable object Start thread
Single vs. Multiple Threads
Using single thread:
in method actionPerformed: ... for (int i=0; i<10; i++) { ”draw single bullet”; Thread.sleep(500); } ...
Using multiple threads: In method actionPerformed: Runnable r = new Runnable() { public void run() { } } Thread t = new Thread(r); t.start();
QUIZ
public static void main(String[] args) { Runnable r1 = new Producer(); Runnable r2 = new Producer(); Thread t1 = new Thread(r1); Thread t2 = new Thread(r2); t1.start(); t2.start(); } How many threads?
- 1. One
- 2. Two
- 3. Three
- 4. None
- 5. I don’t know
Multiple threads
Starting Two Threads
public static void main(String[] args) { Runnable r1 = new Producer(); Runnable r2 = new Producer(); Thread t1 = new Thread(r1); Thread t2 = new Thread(r2); t1.start(); t2.start(); }
Multithreading
- Threads
- Thread states
- Thread interruption
- Race condition
- Lock
- Built-in lock
- java.util.concurrent library
- Animation example
Thread states
- Each thread has
– State (new, runnable, blocked, dead), and – priority
Thread blocked when
- Sleeping
- Waiting for I/O
- Waiting to acquire lock
- Waiting for condition
Scheduler activates the runnable thread of max priority if
- a thread has completed its time
slice
- a thread has blocked itself
- a thread with higher priority has
become runnable
Thread scheduling
public static void main(String[] args) { Runnable r1 = new Producer(“goddag”); Runnable r2 = new Producer(“farvel”); Thread t1 = new Thread(r1); Thread t2 = new Thread(r2); t1.start(); t2.start(); }
Output depends
- n scheduler:
“goddag” “goddag” “farvel” “farvel” “farvel” “goddag” “farvel” …
public class Producer implements Runnable { public Producer(String a) { greeting = a; } public void run() { try { for (int i = 1; i <= 10; i++) { System.out.println(i + ": " + greeting); Thread.sleep(100); } } catch (InterruptedException e) {} } private String greeting; }
QUIZ
Thread T1 based on run method public void run { try { Thread.sleep(100000); } catch (InterruptedException e) {} } Thread T2 based on run method public void run { factor(785678564567385635789) } Which thread(s) are runnable throughout there ”lives” from start to termination?
- 1. T1
- 2. T2
- 3. None
- 4. Both
- 5. I don’t know
Thread scheduling Integer factor method from ”noter” ch. 1 (it is slow)
Multithreading
- Threads
- Thread states
- Thread interruption
- Race condition
- Lock
- Built-in lock
- java.util.concurrent library
- Animation example
Thread interaction
- Recursive Fibonacci
– May take long time – Window freezes
- Compute in separate threads
– Old slow thread may overwrite result from new fast thread? – Interrupt old threads!
ThreadTester3
Terminating Threads
- Thread terminates when run exits
- Or ask thread to finish by calling interrupt
- Thread may check for interrupt by calling
Thread.currentThread().isInterrupted()
- sleep, wait throw InterruptedException
when thread is interrupted
private Thread t = null; public void actionPerformed(ActionEvent e) { if (t!=null) t.interrupt(); Runnable r = new Runnable() { public void run() { try { long res = fib(Integer.parseInt(input.getText())); if (!Thread.currentThread().isInterrupted()) recResult.setText(res+""); } catch (InterruptedException e) {} } }; t = new Thread(r); t.start(); } private long fib(int n) throws InterruptedException { if (Thread.currentThread().isInterrupted()) throw new InterruptedException(); if (n <= 1) return 1; else return fib(n - 1) + fib(n - 2); } Code of anonymous class implementing ActionListener
QUIZ
public class Test1 implements Runnable { public void run() { try { for (int i=1; i<=10; i++) { System.out.println(i); Thread.sleep(1000); } } catch (InterruptedException e) { } } } The catch statement is empty?
- 1. Compiler error
- 2. Legal code, but better style to omit try-catch
- 3. Legal code, try-catch is necessary, but empty catch is bad style
- 4. Legal code, try-catch is necessary, empty catch is good style
- 5. I don’t know
Thread termination
Multithreading
- Threads
- Thread states
- Thread interruption
- Race condition
- Lock
- Built-in lock
- java.util.concurrent library
- Animation example
Shared Resource
Producer Thread ”goddag” Producer Thread ”farvel” Consumer Thread Queue
- bject
Bounded Queue: max 10 elements
Producer Thread
int i = 1; while (i <= 100) { if (!queue.isFull()) { queue.add(i + ": " + greeting); i++; } Thread.sleep((int)(Math.random() * DELAY)); } Producer Thread ”goddag” Producer Thread ”farvel” Consumer Thread Queue
- bject
Bounded Queue: max 10 elements
Consumer Thread
int i = 1; while (i <= 200) { if (!queue.isEmpty()) { Object greeting = queue.remove(); System.out.println(greeting); i++; } Thread.sleep((int)(Math.random() * DELAY)); } Producer Thread ”goddag” Producer Thread ”farvel” Consumer Thread Queue
- bject
Bounded Queue: max 10 elements
- Expected Program
Output
1: goddag 1: farvel 2: goddag 3: goddag ... 99: farvel 100: farvel
- Possible output
... 10: goddag 11: farvel ... 15: goddag 11: farvel ...
- Why?
Queue: Circular Array Implementation
public void add(E newValue) { elements[tail] = newValue; tail++; size++; if (tail == elements.length) { tail = 0; } } <junk> <junk> <junk> 4 3 2 1 <junk>
Head: Tail:
3 2 1 <junk> <junk> <junk> <junk> 4
Tail: Head:
Race Condition
- First thread calls add and executes
elements[tail] = newValue; First thread at end of time slice
- Second thread calls add and executes
elements[tail] = newValue; tail++; Second thread at end of time slice
- First thread executes
tail++;
QUIZ
Producer Thread:
BoundedQueue<String> queue = new BoundedQueue<String>(10); for (int i = 1; i <= 100; i++) { queue.add(i + ": " + greeting); Thread.sleep((int)(Math.random() * DELAY)); }
Consumer Thread:
BoundedQueue<String> queue = new BoundedQueue<String>(10); for (int i = 1; i <= 100; i++) { Object greeting = queue.remove(); System.out.println(greeting); Thread.sleep((int)(Math.random() * DELAY)); } Race condition Could race condition occur when running these thread in parallel?
- 1. Yes
- 2. No
- 3. I don’t know
Multithreading
- Threads
- Thread states
- Thread interruption
- Race condition
- Lock
- Built-in lock
- java.util.concurrent library
- Animation example
Locks
- Thread can acquire lock
- When another thread tries to acquire same lock,
it blocks
- When first thread releases lock, other thread is
unblocked and tries again
- Two kinds of locks
– Objects of class implementing java.util.concurrent.Lock interface type, usually ReentrantLock – Locks that are built into every Java object
private Lock aLock = new ReentrantLock(); . . . public void add(E newValue) { aLock.lock(); try { elements[tail] = newValue; tail++; size++; if (tail==elements.length) tail = 0; } finally { aLock.unlock(); } } Consumer or producer thread executing lock() has exclusive access to add/remove methods – even when time slice is up – until unlock() public E remove() { aLock.lock(); try { E r = (E) elements[head]; head++; size--; if (head==elements.length) head = 0; return r; } finally { aLock.unlock(); } }
Producer Thread
int i = 1; while (i <= 100) { if (!queue.isFull()) { queue.add(i + ": " + greeting); i++; } Thread.sleep((int)(Math.random() * DELAY)); }
Good: add is protected by lock Bad: Another producer thread may fill up the queue between isFull() check and add() Solution: Must move isFull() check inside protected add()
QUIZ
public void add(E newValue) throws InterruptedException { aLock.lock(); try { while( isFull() ) { Thread.sleep(1000); } ... } finally {aLock.unlock();} }
Dead lock Does it work to put isfull() check inside lock protected add()?
- 1. No, race condition may still occur
- 2. Yes, race condition cannot occur, and this code works fine
- 3. No, race condition cannot occur – but a new problem arises…
- 4. I don’t know
Using condition object to avoid deadlock
private Lock aLock = new ReentrantLock(); private Condition spaceAvailableCondition = aLock.newCondition(); public void add(E newValue) throws InterruptedException { aLock.lock(); try { while (isFull()) spaceAvailableCondition.await(); . . . } finally {aLock.unlock();} } public E remove() throws InterruptedException { aLock.lock(); try { . . . spaceAvailableCondition.signalAll(); return r; } finally {aLock.unlock();} } Calling await blocks the thread and releases the lock Calling signalAll() unblocks all threads awaiting this condition (they remain blocked until getting the lock)
Multithreading
- Threads
- Thread states
- Thread interruption
- Race condition
- Lock
- Built-in lock
- java.util.concurrent library
- Animation example
Object Locks
- Each object has a lock
- Calling a synchronized method acquires lock of implicit parameter
- Leaving the synchronized method releases lock
- Easier than explicit Lock objects
public class BoundedQueue<E> { public synchronized void add(E newValue) { ... } public synchronized E remove() { ... } ... }
Object Locks
- Each implicit lock has one associated (anonymous)
condition object
- wait() blocks current thread and adds it to wait set
- notifyAll() unblocks waiting threads
public synchronized void add(E newValue) throws InterruptedException { while (isFull()) wait(); elements[tail] = anObject; . . . notifyAll(); }
Just one condition object Used by both threads waiting due to full queue and due to empty queue
QUIZ
Thread blocking What is not reason for blocking a thread?
- 1. Sleeping
- 2. Waiting for I/O
- 3. Time slice is up
- 4. Waiting to acquire lock
- 5. Waiting for a condition
- 6. I don’t know
QUIZ
When is InterruptedException thrown?
- 1. when Thread.sleep(..) returns
- 2. when <condition>.await() returns
- 3. when other thread calls this threads interrupt method
- 4. when other thread calls this threads interrupt method
while this thread is blocked
- 5. I don’t know
Thread interruption
Multithreading
- Threads
- Thread states
- Thread interruption
- Race condition
- Lock
- Built-in lock
- java.util.concurrent library
- Animation example
Use java.util.concurrent library
Main thread:
BlockingQueue<String> queue = new LinkedBlockingQueue<String>(10);
Producer Thread:
for (int i = 1; i <= 100; i++) { queue.put(i + ": " + greeting); Thread.sleep((int)(Math.random() * DELAY)); }
Consumer Thread:
for (int i = 1; i <= 100; i++) { Object greeting = queue.take(); System.out.println(greeting); Thread.sleep((int)(Math.random() * DELAY)); } Synchronized queue with space for 10 elements Producer thread is made to wait until queue has available space Consumer thread is made to wait until queue is nonempty
Multithreading
- Threads
- Thread states
- Thread interruption
- Race condition
- Lock
- Built-in lock
- java.util.concurrent library
- Animation example
Algorithm Animation
- Use thread to make progress in algorithm
- Display algorithm state
- Example: Animate MergeSorter (similar to java.util.Arrays.sort)
- Pause inside compare method
- Pass custom comparator
Comparator<Double> comp = new Comparator<Double>() { public int compare(Double d1, Double d2) { draw current state pause thread return d1.compareTo(d2); } };
Algorithm Animation
public class Sorter implements Runnable { public Sorter(Double[] values, ArrayComponent panel) { this.values = values; this.panel = panel; } public void run() { Comparator<Double> comp = new Comparator<Double>() { public int compare(Double d1, Double d2) { panel.setValues(values, d1, d2); try { Thread.sleep(DELAY); } catch (InterruptedException exception) { Thread.currentThread().interrupt(); } return d1.compareTo(d2); }; MergeSorter.sort(values, comp); panel.setValues(values, null, null); } private Double[] values; private ArrayComponent panel; private static final int DELAY = 100; } array being sorted
Pausing and Running the Animation
- Want to pause animation until "Run" or "Step"
button is clicked
- Need to coordinate UI thread, animation thread
- Try to use built-in thread-safe construct in
java.util.concurrent
- Trick: Use a blocking queue
- Button click adds string "Run" or "Step" to queue
- Animation thread calls take on the queue, blocks
if no string inserted BlockingQueue<String> queue;
User Interface Thread
stepButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { queue.add("Step"); runButton.setEnabled(true); } }); runButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { runButton.setEnabled(false); queue.add("Run"); } });
Animation Thread
public int compare(Double d1, Double d2) { try { String command = queue.take(); if (command.equals("Run")) { Thread.sleep(DELAY); if (!"Step".equals(queue.peek())) queue.add("Run"); } } catch (InterruptedException exception) { Thread.currentThread().interrupt(); } panel.setValues(values, d1, d2); return d1.compareTo(d2); } ... private BlockingQueue<String> queue;