multithreading horstmann ch.9. multithreading threads thread states thread interruption race...
TRANSCRIPT
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 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.None
2.One
3.Two
4.Three
5. I don’t know
Starting Two Threadspublic 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 schedulingpublic 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 on 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)
become blocked?
1.None
2.T1
3.T2
4.Both
5. I don’t know
factor method from ”noter” ch. 1
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 callThread.currentThread().isInterrupted()
• sleep, wait throw InterruptedException when thread 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
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 object
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));
}
Consumer Thread
int i = 1;while (i <= 100) { if (!queue.isEmpty()) { Object greeting = queue.remove(); System.out.println(greeting); i++; } Thread.sleep((int)(Math.random() * DELAY)); }
• Expected Program Output
1: goddag1: farvel2: 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; } }
Race Condition• First thread calls add and executes
elements[tail] = newValue; First thread at end of time slice
• Second thread calls add and executeselements[tail] = newValue;
tail++; Second thread at end of time slice
• First thread executestail++;
QUIZProducer 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)); }
Could race condition occur when running these thread in parallel?1.Yes2.No3.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();}}
Does it work?
1: No, race condition may still occur
2: Yes, race condition cannot occur, and this code works fine
3: ??? – race condition cannot occur – but a new problem arises…
4: I don’t know
isfull() check is now inside lock protected add()
QUIZ
public void add(E newValue) throws InterruptedException { aLock.lock(); try { while( isFull() ) { Thread.sleep(1000); } ... } finally {aLock.unlock();}}
Does it work?
1: No, race condition may still occur
2: Yes, race condition cannot occur, and this code works fine
3: ??? – race condition cannot occur – but a new problem arises…
4: I don’t know
isfull() check is now inside lock protected add()
”Deadlock”: Since the queue remains locked, no consumer thread can execute remove() and make isFull() false
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 objectUsed by both threads waiting due to full queue and due to
empty queue
QUIZWhat 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
QUIZWhen is InterruptedException thrown?
1. when Thread.sleep(..) returns
2. when <condition>.await() returns
3. when other thread calls this threads interrupt method while this thread is blocked
4. I don’t know
Multithreading
• Threads• Thread states• Thread interruption• Race condition• Lock• Built-in lock
• java.util.concurrent library• Animation example
Use java.util.concurrent libraryMain 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 insertedBlockingQueue<String> queue;
User Interface ThreadstepButton.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 Threadpublic 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;