multithreading : synchronization. avanced programming 2004, based on lys stefanus’s slides slide...

32
Multithreading : synchronization

Upload: melvyn-taylor

Post on 03-Jan-2016

223 views

Category:

Documents


1 download

TRANSCRIPT

Multithreading :synchronization

slide 4.2

Avanced Programming 2004, Based on LYS Stefanus’s slides

Solving the Race Condition Problem

• A thread must be able to lock an object temporarily

• When a thread has the object locked, no other thread can modify the state of the object.

• In Java, use synchronized methods to do this

• Tag all methods that contain thread-sensitive code with the keyword synchronized

slide 4.3

Avanced Programming 2004, Based on LYS Stefanus’s slides

Synchronized Methodspublic class BankAccount {

public synchronized void deposit(double amount) { . . .

}

public synchronized void withdraw(double amount) { . . .

}

. . .

}

slide 4.4

Avanced Programming 2004, Based on LYS Stefanus’s slides

With synchronization, the final balance is always correct!

slide 4.5

Avanced Programming 2004, Based on LYS Stefanus’s slides

Synchronized Methods• By declaring both the deposit and withdraw

methods to be synchronized

Our program will run correctly

Only one thread at a time can execute either method on a given object

When a thread starts one of the methods, it is guaranteed to execute the method to completion before another thread can execute a synchronized method on the same object.

slide 4.6

Avanced Programming 2004, Based on LYS Stefanus’s slides

• By executing a synchronized method:

The thread acquires the object lock.

No other thread can acquire the lock.

No other thread can modify the state of the object until the first thread is finished.

• Every object in Java has a lock associated with it. Every object can maintain a list of waiting threads.

slide 4.7

Avanced Programming 2004, Based on LYS Stefanus’s slides

Visualization of Synchronized Thread Behavior

• Imagine the object is a restroom that only one person can use at a time

• The threads are people • If the restroom is empty, a person may enter • If a second person finds the restroom locked, the second

person must wait until it is empty • If multiple people want to gain access to the restroom ,

they all wait outside • The people may not form an orderly queue • A randomly chosen person may gain access when the

restroom becomes available again

slide 4.8

Avanced Programming 2004, Based on LYS Stefanus’s slides

Deadlock

• A deadlock occurs if no thread can proceed because each thread is waiting for another to do some work first.

• In other words, a deadlock occurs when two threads end up waiting for each other to release a lock they need. Since neither one can proceed, neither one can release the lock it holds, and they both stop running.

• When you are synchronizing threads, you must be careful to avoid deadlock.

slide 4.9

Avanced Programming 2004, Based on LYS Stefanus’s slides

• BankAccount example public synchronized void withdraw(double amount) { while (balance < amount) //wait for balance to grow . . . }

slide 4.10

Avanced Programming 2004, Based on LYS Stefanus’s slides

• The method can lead to deadlock

• The thread sleeps to wait for balance to grow, but it still has the lock

• No other thread can execute the synchronized deposit method

• If a thread tries to call deposit, it is blocked until the withdraw method exits

• withdraw method can't exit until it has funds available

• DEADLOCK occurs!

slide 4.11

Avanced Programming 2004, Based on LYS Stefanus’s slides

Avoiding Deadlock

• The wait method temporarily releases the object lock and deactivates the thread

• Restroom analogy Don't want the person in the restroom to go

to sleep if there is no toilet paper. Think of the person giving up and leaving This gives another person a chance to enter

and refill the toilet paper

slide 4.12

Avanced Programming 2004, Based on LYS Stefanus’s slides

withdraw Method to Avoid Deadlock with wait()

public synchronized void withdraw(double amount) throws InterruptedException{ while (balance < amount) wait(); ...}

slide 4.13

Avanced Programming 2004, Based on LYS Stefanus’s slides

Wait and NotifyAll • A thread that calls wait is in a blocked state

• It will not be activated by the thread scheduler until it is unblocked

• It is unblocked when another thread calls notifyAll

• When a thread calls notifyAll, all threads waiting on the object are unblocked

• Only the thread that has the lock can call notifyAll

slide 4.14

Avanced Programming 2004, Based on LYS Stefanus’s slides

Restroom wait/notifyAll Analogy

• The thread calling wait() corresponds to the person who enters the restroom and finds there is no toilet paper

• The person then leaves the restroom and waits outside

• Other people may enter and leave, but the first person just waits

• Eventually an attendant enters the restroom, refills the toilet paper, and shouts a notification

• All the waiting people compete for the restroom

slide 4.15

Avanced Programming 2004, Based on LYS Stefanus’s slides

File BankAccountThreadTest.java (Modified, Using synchronized methods)

/** This program runs four threads that deposit and withdraw money from the same bank account. */public class BankAccountThreadTest { public static void main(String[] args) {

slide 4.16

Avanced Programming 2004, Based on LYS Stefanus’s slides

BankAccount account = new BankAccount();

DepositThread t0 = new DepositThread(account, 100); WithdrawThread t1 = new WithdrawThread(account, 100); DepositThread t2 = new DepositThread(account, 100); WithdrawThread t3 = new WithdrawThread(account, 100);

t0.start(); t1.start(); t2.start(); t3.start(); } //end main} // end class

slide 4.17

Avanced Programming 2004, Based on LYS Stefanus’s slides

File BankAccount.java (modified)/** A bank account has a balance that can be changed by deposits and withdrawals.*/public class BankAccount { /** Constructs a bank account with a zero balance */ public BankAccount() { balance = 0; } /** Deposits money into the bank account. @param amount the amount to deposit */

slide 4.18

Avanced Programming 2004, Based on LYS Stefanus’s slides public synchronized void deposit(double amount) {

System.out.print("Depositing " + amount);

double newBalance = balance + amount;

System.out.println(", new balance is " + newBalance);

balance = newBalance;

notifyAll();

}

/**

Withdraws money from the bank account.

@param amount the amount to withdraw

*/

public synchronized void withdraw(double amount)

throws InterruptedException {

while (balance < amount)

wait();

System.out.print("Withdrawing " + amount);

double newBalance = balance - amount;

System.out.println(", new balance is " + newBalance);

balance = newBalance;

}

slide 4.19

Avanced Programming 2004, Based on LYS Stefanus’s slides

/** Gets the current balance of the bank account. @return the current balance */ public synchronized double getBalance() { return balance; } private double balance;

} // end class

slide 4.20

Avanced Programming 2004, Based on LYS Stefanus’s slides

Be careful!

• A common error is to have threads call wait without matching calls to notifyAll by other threads. Whenever you call wait, ask yourself which call to notifyAll will notify your thread.

• The thread that calls notifyAll must own the lock on the object on which notifyAll is called. Otherwise, an IllegalMonitorStateException is thrown.

slide 4.21

Avanced Programming 2004, Based on LYS Stefanus’s slides

notify( )

• While notifyAll( ) wakes up all threads that are waiting on the object, notify( ) wakes up only a single thread that is waiting on the object. If any threads are waiting on the object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation.

• It's better to use notifyAll( ).

slide 4.22

Avanced Programming 2004, Based on LYS Stefanus’s slides

Complex Deadlocks• Using the wait and notifyAll methods does not solve all

deadlocks.

• The following is an example.

• We have three accounts: account0, account1, and account2; and three transfer threads: t0, t1, and t2.

• A transfer thread transfers money from two accounts into a third.

• t0 repeatedly transfers $500 each from account1 and account2 to account0.

• t1 repeatedly transfers $500 each from account2 and account0 to account1.

• t2 repeatedly transfers $500 each from account0 and account1 to account2.

slide 4.23

Avanced Programming 2004, Based on LYS Stefanus’s slides

• If the three threads take turns and each thread executes one iteration before losing control of the CPU, then the program runs indefinitely:

account0 account1 account2

Initial balance $1000 $1000 $1000

After t0 iteration $2000 $500 $500

After t1 iteration $1500 $1500 0

After t2 iteration $1000 $1000 $1000

slide 4.24

Avanced Programming 2004, Based on LYS Stefanus’s slides

• But if it happens that t0 executes two iterations before t1 and t2 get a chance, then the program deadlocks:

account0 account1 account2

Initial balance $1000 $1000 $1000

After t0 iteration $2000 $500 $500

After t0 iteration $3000 0 0

Now none of the three threads can progress, and a deadlock occurs.

slide 4.25

Avanced Programming 2004, Based on LYS Stefanus’s slides

• Most of the time, the program will carry out the transfers successfully, but once in a while you may be able to observe a deadlock.

• Programmers who create multithreaded programs must make an effort to prove rigorously why their threads cannot deadlock no matter in which order they are executed.

• Running a few experiments is not enough. It can be misleading.

slide 4.26

Avanced Programming 2004, Based on LYS Stefanus’s slides

File BankAccountThreadTest.java/** This program uses three threads that transfer money

between three accounts. It can occasionally deadlock.*/public class BankAccountThreadTest { public static void main(String[] args) { BankAccount account0 = new BankAccount(1000); BankAccount account1 = new BankAccount(1000); BankAccount account2 = new BankAccount(1000);

//... Put your code here ...

}}

slide 4.27

Avanced Programming 2004, Based on LYS Stefanus’s slides

File TransferThread.java/** A transfer thread repeatedly transfers money between three

bank accounts.*/class TransferThread extends Thread { /** Constructs a transfer thread. @param account1 the first account to withdraw @param account2 the second account to withdraw @param account3 the account to deposit @param anAmount the amount to withdraw from each of the first two accounts. */ public TransferThread(BankAccount account1, BankAccount account2, BankAccount account3, double anAmount) { //... Put your code here ... }

slide 4.28

Avanced Programming 2004, Based on LYS Stefanus’s slides

public void run() { try { for (int i = 1; i <= REPETITIONS && !isInterrupted(); i++) { // ... Put your code here ... sleep(DELAY); } } catch (InterruptedException exception) { } }

private BankAccount from1, from2, to; private double amount; private static final int REPETITIONS = 10; private static final int DELAY = 10;}

slide 4.29

Avanced Programming 2004, Based on LYS Stefanus’s slides

/** A bank account has a balance that can be changed by deposits and withdrawals.*/public class BankAccount { /** Constructs a bank account with a given balance @param initialBalance the initial balance */ public BankAccount(double initialBalance) { balance = initialBalance; }

File BankAccount.java

slide 4.30

Avanced Programming 2004, Based on LYS Stefanus’s slides

/** Deposits money into the bank account. @param amount the amount to deposit */ public synchronized void deposit(double amount) { balance = balance + amount; System.out.println(Thread.currentThread().getName() + " Depositing " + amount + ", new balance is " + balance); notifyAll(); }

slide 4.31

Avanced Programming 2004, Based on LYS Stefanus’s slides

/** Withdraws money from the bank account. @param amount the amount to withdraw */ public synchronized void withdraw(double amount) throws InterruptedException { while (balance < amount) { System.out.println(Thread.currentThread().getName() + " Waiting..."); wait(); } balance = balance - amount; System.out.println(Thread.currentThread().getName() + " Withdrawing " + amount + ", new balance is " + balance); }

slide 4.32

Avanced Programming 2004, Based on LYS Stefanus’s slides

/** Gets the current balance of the bank account. @return the current balance */ public synchronized double getBalance() { return balance; } private double balance;

} //end class