Presentation is loading. Please wait.

Presentation is loading. Please wait.

CSE 219 Computer Science III Multithreaded Issues.

Similar presentations


Presentation on theme: "CSE 219 Computer Science III Multithreaded Issues."— Presentation transcript:

1 CSE 219 Computer Science III Multithreaded Issues

2 Java Thread Issues We’ve used threads naively Many things to consider when using multithreading in an application: –Swing & threads –race conditions –locking threads –deadlock

3 Swing & Threads NOTE: Swing is not thread-safe We have to be careful when mixing GUIs (Swing) and Concurrency (Threads) The screen should never “freeze” The program should always be responsive to user interaction –no matter what it may currently be doing

4 Race Conditions Threads are independent pieces of control operating on the same data. One thread could interfere with another thread’s work –results in corrupted data –called a race condition Common issue in Consumer – Producer relationships –one thread is the producer, adding to a shared data structure –one thread is the consumer, using a shared data structure 2003 Blackout problem? Race Conditions in software: –http://www.securityfocus.com/news/8412http://www.securityfocus.com/news/8412 When do race conditions happen? –when transactions lack atomicity

5 Atomicity A property of a transaction An atomic transaction happens either completely or not at all What’s a transaction? –code execution (ex: method) that changes stored data Ex: instance variables, static variables, database

6 Example: A Corruptible Bank BuggedTransferer -bank:BadBank -fromAccount:int +$MAX:double +$DELAY:int +run():void BadBank -account: double[] +$INIT_BALANCE:double +$NUM_ACCOUNTS:int +transfer(from:int, to:int, double:amount):void -getTotalBalance():double > Runnable Assumptions: –We will create a single BadBank and make random transfers, each in separate threads 100 1

7 public class BadBank { public static int INIT_BALANCE = 1000, NUM_ACCOUNTS = 100; private double[] accounts = new double[NUM_ACCOUNTS]; public BadBank() { for (int i = 0; i < NUM_ACCOUNTS; i++) accounts[i] = INIT_BALANCE; } public void transfer(int from, int to, double amount) { if (accounts[from] < amount) return; accounts[from] -= amount; System.out.print(Thread.currentThread()); System.out.printf("%10.2f from %d to %d",amount,from,to); accounts[to] += amount; double total = getTotalBalance(); System.out.printf(" Total Balance: %10.2f%n", total); } private double getTotalBalance() { double sum = 0; for (double a : accounts) sum += a; return sum; } BadBank.java

8 public class BuggedTransferer implements Runnable { private BadBank bank; private int fromAccount; public static final double MAX = 1000; public static final int DELAY = 100; public BuggedTransferer(BadBank b, int from) { bank = b; fromAccount = from; } public void run() { try { while(true) { int toAccount = (int)(bank.NUM_ACCOUNTS * Math.random()); double amount = MAX * Math.random(); bank.transfer(fromAccount, toAccount, amount); Thread.sleep((int)(DELAY*Math.random())); } } catch(InterruptedException e) {/*SQUELCH*/} } BuggedTransferer.java

9 public class AtomiclessDriver { public static void main(String[] args) { BadBank b = new BadBank(); for (int i = 0; i < BadBank.NUM_ACCOUNTS; i++) { BuggedTransferer bT = new BuggedTransferer(b,i); Thread t = new Thread(bT); t.start(); } AtomiclessDriver.java

10 What results might we get? …Total Balance: 100000.00 …Total Balance: 99431.55 …Total Balance: 99367.34 … Why might we get invalid balance totals? race conditions operations on shared data may lack atomicity Bottom line: a method or even a single statement is not an atomic operation this means that the statement can be interrupted during its operation

11 A single statement? Compiled into multiple low-level statements To see: javap –c –v BadBank Ex: accounts[from] -= amount; … 21 aload_0 22 getfield #3 25 iload_1 26 dup2 27 daload 28 dload_3 29 dsub 30 dastore …

12 Race Condition Example Thread 1 & 2 are in transfer at the same time. Thread 1Thread 2 aload_0 getfield #3 iload_1 dup2 daload dload_3 aload_0 getfield #3 iload_1 dup2 daload dload_3 dsub dastore dsub dastore What’s the problem? This might store corrupted data

13 How do we guarantee atomicity? By locking methods or code blocks What is a lock? –a thread gets a lock on critical shared code –only one thread may execute locked code at a time Two techniques: 1.Locking code blocks via the ReentrantLock class new to Java in 1.5 2.Synchronizing methods or code blocks Synchronization is easier to use, ReentrantLock with Condition classes are more powerful Can we lock an object? –yes, we’ll see how in a few moments

14 ReentrantLock Basic structure to lock critical code: ReentrantLock myLock = new ReentrantLock(); … myLock.lock(); try { // CRITICAL AREA TO BE ATOMICIZED } finally { myLock.unLock(); } When a thread enters this code: –if no other lock exists, it will execute the critical code –otherwise, it will wait until previous locks are unlocked

15 Updated transfer method public class GoodBank { private ReentrantLock bankLock = new ReentrantLock(); private double[] accounts = new double[NUM_ACCOUNTS]; … public void transfer(int from, int to, double amount) { bankLock.lock(); try { if (accounts[from] < amount) return; accounts[from] -= amount; System.out.print(Thread.currentThread()); System.out.printf("%10.2f from %d to%d",amount,from,to); accounts[to] += amount; double total = getTotalBalance(); System.out.printf(" Total Balance: %10.2f%n", total); } finally{ bankLock.unlock(); } } } NOTE: This works because transfer is the only mutator method for accounts –What if there were more than one? then we’d have to lock the accounts object

16 Synchronizing Methods public synchronized void deposit(int d) { … } A monitor (object with synchronized methods) allows one thread at a time to execute a synchronized method on the object –Locks the method when the synchronized method is invoked –Only one synchronized method may be active on an object at once –All other threads attempting to invoke synchronized methods must wait –When a synchronized method finishes executing, the lock on the object is released and the monitor lets the highest-priority ready thread proceed Note: Java also allows synchronized blocks of code. Ex: synchronized (this) { while (blah blah blah) blah blah blah }

17 Synchronized transfer method public class SynchronizedBank { … public synchronized void transfer (int from, int to, double amount) { if (accounts[from] < amount) return; accounts[from] -= amount; System.out.print(currentThread()); System.out.printf("%10.2f from %d to%d", amount,from,to); accounts[to] += amount; double total = getTotalBalance(); System.out.printf(" Total Balance: %10.2f%n", total); } } }

18 Locking Data synchronized is fine for locking methods, but what about data? –the synchronized keyword cannot be used on variables –Ex: the account variable to lock/unlock data we can use a combination of approaches: –use only synchronized methods for manipulating shared data OR –define a method for acquiring a lock on data –while an object is locked, make all other threads wanting to use it wait –define a method for releasing a piece (or pieces) of data, notifying all other threads when done OR –declare variables as volatile

19 public class GoodBank { private double[] accounts = new double[NUM_ACCOUNTS]; private boolean inUse = false; public synchronized void acquire() throws InterruptedException { while (inUse) wait(); inUse = true; notify(); } public synchronized void release() { inUse = false; notify(); } // ALL METHODS USING accounts MUST GET LOCKS FIRST Locked accounts object

20 // SOMEWHERE INSIDE GoodBank class acquire(); … // DO LOTS OPERATIONS THAT … // MAY MANIPULATE THE accounts … // OBJECT AS PART OF SOME … // GREATER ALGORITHM release(); Using Object Locks

21 wait and notifyAll wait() blocks the current thread (potentially forever) –another thread must notify it –all Object s have a wait method that can be called public synchronized void acquire() throws InterruptedException { while (inUse) wait(); inUse = true; notify(); } notify() & notifyAll() unblock a thread or all threads waiting on the current object –must be called at the end of a synchronized method, else you may get an IllegalMonitorStateException public synchronized void release(Object requestor) { inUse = false; notifyAll(); }

22 notify and notifyAll A thread T 1 blocked by wait() is made runnable when another thread T 2 invokes notifyAll() on the object T 1 operates on. notify() wakes up one of the waiting threads notifyAll() wakes up all waiting threads Once a thread is notified –it attempts to obtain lock again, and if successful it gets to lock all other threads out

23 public class GoodBank { private volatile double[] accounts = new double[NUM_ACCOUNTS]; The volatile keyword guarantees single threaded use More overhead for JVM, so slower Mixed results for use Alternative: volatile

24 What’s the worst kind of race condition? One that rarely happens, but causes devastating effects Hard to find, even during extensive testing Can be hard to simulate, or deliberately produce –depends on thread scheduler, which we don’t control Surface only during catastrophes Moral of the story, don’t rely on thread scheduler –make sure your program is thread safe should be determined logically, before testing

25 Dining Philosophers Problem 5 philosophers 5 forks 5 plates 1 large bowl of spaghetti in center

26 Deadlocks and other matters Deadlock: –a thread T 1 holds a lock on L 1 and wants lock L 2 AND –a thread T 2 holds a lock on L 2 and wants lock L 1. –problem: a thread holds a lock on one or more objects when it invoked wait() on itself Morals of the story: –don’t let waiting threads lock other data release all their locks before going to wait there are all sorts of proper algorithms for thread lock ordering (you’ll see if you take CSE 306) –a thread cannot be resumed if a wait is not matched by a notify


Download ppt "CSE 219 Computer Science III Multithreaded Issues."

Similar presentations


Ads by Google