Upload
kelley-greer
View
226
Download
5
Embed Size (px)
DESCRIPTION
3/70 강원대학교 Thread 스레드는 프로그램을 병렬로 실행할 수 있게 해준다 병렬로 실행되는 쓰레드들은 프로그램 코드와 메모리 데이 터 ( 객체, 상수 ) 를 공유한다. 각각의 스레드는 자기만의 스택 ( 지역변수 ) 을 가지고 있다
Citation preview
1/70강원대학교
14 주
멀티쓰레딩Multithreading
2/70
Process and Thread
강원대학교
http://www.javamex.com/tutorials/threads/how_threads_work.shtml
3/70강원대학교
Thread
• 스레드는 프로그램을 병렬로 실행할 수 있게 해준다• 병렬로 실행되는 쓰레드들은 프로그램 코드와 메모리
데이터 ( 객체 , 상수 ) 를 공유한다 . • 각각의 스레드는 자기만의 스택 ( 지역변수 ) 을 가지고
있다
4/70강원대학교
날짜 시간 출력 코드
final int REPETITIONS = 10;String greeting = "Hello!";
for (int i = 1; i <= REPETITIONS; i++) { Date now = new Date(); System.out.println(now + " " + greeting); Thread.sleep(DELAY); }
5/70강원대학교
단일 쓰레드 실행
지금까지 해 온 방식대로 코드를 main 메소드에 적어줌
main 메소드를 실행하는 쓰레드가 하나 존재하게 됨
public static void main(String[] agrs) {코드
}
6/70강원대학교
단일 쓰레드 실행
Fri May 28 15:21:35 KST 2010 Hello!Fri May 28 15:21:36 KST 2010 Hello!Fri May 28 15:21:37 KST 2010 Hello!Fri May 28 15:21:38 KST 2010 Hello!Fri May 28 15:21:39 KST 2010 Hello!Fri May 28 15:21:40 KST 2010 Hello!Fri May 28 15:21:41 KST 2010 Hello!Fri May 28 15:21:42 KST 2010 Hello!Fri May 28 15:21:43 KST 2010 Hello!Fri May 28 15:21:44 KST 2010 Hello!
7/70강원대학교
두 개 이상의 쓰레드 실행기본 쓰레드에서 실행되는 main 메소드에서 추가적인 쓰레드를 만들어 실행하도록 해 줌
public static void main(String[] agrs) {Thread t1 = new Thread(); // 표준라이브러리의 Thread 클래스 !Thread t2 = new Thread();t1.start();t2.start();
}
기본 쓰레드와 t1, t2 등 모두 세 개의 쓰레드가 존재하게 됨기본 쓰레드는 위 코드를 실행한 후 종료t1 과 t2 쓰레드는 Thread 클래스의 run 메소드를 실행함Thread 클래스의 run 메소드는 아무 일도 하지 않음
8/70강원대학교
두 개 이상의 쓰레드 실행t1, t2 쓰레드가 의미 있는 일을 하게 하려면 Thread 의 run 메소드를 재정의함
public class MyThread extends Thread {public void run() {
의미 있는 일을 하는 코드}
}
public static void main(String[] agrs) {Thread t1 = new MyThread();Thread t2 = new MyThread();t1.start();t2.start();
}
9/70강원대학교
두 개 이상의 쓰레드 실행t1, t2 쓰레드가 의미 있는 일을 하게 하려면 Thread 의 run 메소드를 재정의함
public class MyThread extends Thread {public void run() {
일 초에 한 번씩 현재 시각을 출력하는 문장}
}
public static void main(String[] agrs) {Thread t1 = new MyThread();Thread t2 = new MyThread();t1.start();t2.start();
}
기본 쓰레드
t1t2
종료
10/70강원대학교
두 쓰레드 실행
Fri May 28 15:24:09 KST 2010 Hello!Fri May 28 15:24:09 KST 2010 Hello!Fri May 28 15:24:10 KST 2010 Hello!Fri May 28 15:24:10 KST 2010 Hello!Fri May 28 15:24:11 KST 2010 Hello!Fri May 28 15:24:11 KST 2010 Hello!Fri May 28 15:24:12 KST 2010 Hello!Fri May 28 15:24:12 KST 2010 Hello!Fri May 28 15:24:13 KST 2010 Hello!Fri May 28 15:24:13 KST 2010 Hello!Fri May 28 15:24:14 KST 2010 Hello!Fri May 28 15:24:14 KST 2010 Hello!
11/70강원대학교
두 개 이상의 쓰레드가 서로 다른 일을 할 수 도 있다 .public class Thread1 extends Thread {
public void run() {일 초에 한 번씩 현재 시각을 출력하는 문장
}}public class Thread2 extends Thread {
public void run() {음악을 연주하는 문장
}}public static void main(String[] agrs) {
Thread t1 = new Thread1();Thread t2 = new Thread2();t1.start();t2.start();
}
기본 쓰레드
t1t2
종료
12/70강원대학교
쓰레드를 실행하는 다른 방법1. Runnable 인터페이스를 구현하는 클래스를 정의하고
수행할 작업을 run 메소드에 적어준다 .
// 표준 라이브러리에 정의되어 있는 인터페이스public interface Runnable{ void run();}
public class MyRunnable implements Runnable { public void run() { // 할 일 } }
13/70강원대학교
Running a Thread3. 정의된 클래스 객체를 구성한다 .
4. Runnable 객체를 인자로 삼아 Thread 객체를 구성한다 .
5. Thread 에 start 메소들를 호출한다 .
Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
14/70강원대학교
GreetingRunnable 뼈대
public class GreetingRunnable implements Runnable{ public GreetingRunnable(String aGreeting) { greeting = aGreeting; }
public void run() {
for (int i = 1; i <= 10; i++) {System.out.println(greeting);Thread.sleep(1000);
}
private String greeting; }
15/70강원대학교
sleep
• 쓰레드를 잠시 중단시키기 위해서는 Thread 클래스의 sleep 메소드 호출
• 이 메소드는 InterruptedException 을 던지는 수가 있음 – 확인예외이므로 예외처리 필수
Thread.sleep(milliseconds)
16/70강원대학교
Generic run Method
public void run() { try { Task statements } catch (InterruptedException exception) {
예외 처리 }}
17/70강원대학교
File GreetingRunnable.java01: import java.util.Date;02: 03: /**04: A runnable that repeatedly prints a greeting.05: */06: public class GreetingRunnable implements Runnable07: {08: /**09: Constructs the runnable object.10: @param aGreeting the greeting to display11: */12: public GreetingRunnable(String aGreeting)13: {14: greeting = aGreeting;15: }16: 17: public void run()18: {
18/70강원대학교
File GreetingRunnable.java19: try20: {21: for (int i = 1; i <= REPETITIONS; i++)22: {23: Date now = new Date();24: System.out.println(now + " " + greeting);25: Thread.sleep(DELAY); 26: }27: }28: catch (InterruptedException exception)29: {30: }31: }32: 33: private String greeting;34: 35: private static final int REPETITIONS = 10;36: private static final int DELAY = 1000;37: }
19/70강원대학교
File GreetingThreadTester.java01: import java.util.Date;02: 03: /**04: This program tests the greeting thread by running two05: threads in parallel.06: */07: public class GreetingThreadTester08: {09: public static void main(String[] args)10: {11: GreetingRunnable r1 = new GreetingRunnable("Hello, World!");12: GreetingRunnable r2 = new GreetingRunnable("Goodbye, World!");
20/70강원대학교
File GreetingThreadTester.java13: Thread t1 = new Thread(r1);14: Thread t2 = new Thread(r2);15: t1.start();16: t2.start();17: }18: }19:
21/70강원대학교
OutputThu Dec 28 23:12:03 PST 2004 Hello, World! Thu Dec 28 23:12:03 PST 2004 Goodbye, World! Thu Dec 28 23:12:04 PST 2004 Hello, World! Thu Dec 28 23:12:05 PST 2004 Hello, World! Thu Dec 28 23:12:04 PST 2004 Goodbye, World! Thu Dec 28 23:12:05 PST 2004 Goodbye, World! Thu Dec 28 23:12:06 PST 2004 Hello, World! Thu Dec 28 23:12:06 PST 2004 Goodbye, World! Thu Dec 28 23:12:07 PST 2004 Hello, World! Thu Dec 28 23:12:07 PST 2004 Goodbye, World! Thu Dec 28 23:12:08 PST 2004 Hello, World! Thu Dec 28 23:12:08 PST 2004 Goodbye, World! Thu Dec 28 23:12:09 PST 2004 Hello, World! Thu Dec 28 23:12:09 PST 2004 Goodbye, World! Thu Dec 28 23:12:10 PST 2004 Hello, World! Thu Dec 28 23:12:10 PST 2004 Goodbye, World! Thu Dec 28 23:12:11 PST 2004 Goodbye, World! Thu Dec 28 23:12:11 PST 2004 Hello, World! Thu Dec 28 23:12:12 PST 2004 Goodbye, World! Thu Dec 28 23:12:12 PST 2004 Hello, World!
22/70강원대학교
2 Runnables 2 Threads vs 1 Runnable and 2 Threads
GreetingRunnable r1 = new GreetingRunnable("Hello, World!");
GreetingRunnable r2 = new GreetingRunnable("Goodbye, World!");
Thread t1 = new Thread(r1);Thread t2 = new Thread(r2);t1.start();t2.start();
Thread t1 = new Thread(r1);Thread t2 = new Thread(r1);t1.start();t2.start();
23/70강원대학교
Thread Scheduler• Thread scheduler 는 각 쓰레드를 짧은 시간
(time slice) 동안 실행 (activate) 시킨다 . • 쓰레드 실행 시간에는 작은 변이가 있을 수 있다
( 특히 입출력 동작시 ).• 쓰레드 실행 순서에는 어떤 보장도 없다 .
24/70강원대학교
쓰레드에 인터럽트 걸기
• t.interrupt();
• InterruptedException 이 발생됨
25/70강원대학교
public void run() { try { Task statements ( 가령 , 음악을 반복해서 연주 ) } catch (InterruptedException exception) {
인터럽트 처리 ( 가령 , 음악 연주를 끝내고 인사말 출력 ) }}
public class GreetingRunnable implements Runnable
GreetingRunnable r = new GreetingRunnable("Hello, World!");Thread t = new Thread(r);t.start();t.interrupt();
main
26/70강원대학교
Thread
• 같은 코드를 실행하는 여러 스레드들은 각각 자기만의 지역변수를 갖는다 .
27/70
두 개의 Runnable 두 개의 스레드public class NumberPrinter implements
Runnable{private static final int REPETITIONS = 100;private static final int DELAY = 1000;
private int number;public NumberPrinter(int n){ number = n; }
public void run() { try{ for (int i = 1; i <= REPETITIONS; i++){ Thread t = Thread.currentThread()
String name = t.getName(); System.out.println(name + ": " + ++number); Thread.sleep(DELAY);
} }catch (InterruptedException exception) {}
}}
강원대학교
public class NumberThreadRunner{ public static void main(String[] args) {
NumberPrinter r1 = new Num-berPrinter(0); Thread t1 = new Thread(r1); t1.setName("t1"); NumberPrinter r2 = new Num-berPrinter(0); Thread t2 = new Thread(r2); t2.setName("t2"); t1.start(); t2.start(); }}
t1: 1t2: 1t2: 2t1: 2t2: 3t1: 3t2: 4t1: 4t1: 5t2: 5t1: 6t2: 6
28/70
한 개의 runnable 두 개의 스레드public class NumberPrinter implements
Runnable{private static final int REPETITIONS = 100;private static final int DELAY = 1000;
private int number;public NumberPrinter(int n){ number = n; }
public void run() { try{ for (int i = 1; i <= REPETITIONS; i++){ Thread t = Thread.currentThread()
String name = t.getName(); System.out.println(name + ": " + ++number); Thread.sleep(DELAY);
} }catch (InterruptedException exception) {}
}}
강원대학교
public class NumberThreadRunner{ public static void main(String[] args) {
NumberPrinter r1 = new Num-berPrinter(0); Thread t1 = new Thread(r1); t1.setName("t1"); Thread t2 = new Thread(r1); t2.setName("t2"); t1.start(); t2.start(); }}
t1: 38t2: 39t1: 40t2: 41t1: 42t2: 43t1: 44t2: 45t1: 46t2: 46t1: 47t2: 47t1: 48t2: 49t1: 50
29/70
한 개의 runnable 두 개의 스레드public class NumberPrinter implements
Runnable{private static final int REPETITIONS = 100;private static final int DELAY = 1000;
private int number;public NumberPrinter(int n){ number = n; }
public void run() { try{ for (int i = 1; i <= REPETITIONS; i++){ Thread t = Thread.currentThread()
String name = t.getName(); System.out.println(name + ": " + i); Thread.sleep(DELAY);
} }catch (InterruptedException exception) {}
}} 강원대학교
public class NumberThreadRunner{ public static void main(String[] args) {
NumberPrinter r1 = new Num-berPrinter(0); Thread t1 = new Thread(r1); t1.setName("t1"); Thread t2 = new Thread(r1); t2.setName("t2"); t1.start(); t2.start(); }}
t1: 1t2: 1t2: 2t1: 2t2: 3t1: 3t1: 4t2: 4t2: 5t1: 5t2: 6t1: 6t2: 7t1: 7
30/70
경쟁 조건 (Race Conditions)
강원대학교
31/70강원대학교
경쟁 조건 (Race Conditions)• 여러 쓰레드가 하나의 자료를 공유하며 자료를
업데이트 할 때 이 자료가 엉망이 될 수 있다 .• 예 : 여러 쓰레드가 은행계좌를 조작할 때
32/70
경쟁 조건 (Race Conditions)
강원대학교
balanceDeposit Thread
Withdraw Thread
deposit withdrawBankAccount
33/70
BankAccount account = new BankAccount();DepositRunnable d = new DepositRunnable(account, AMOUNT, REPE-TITIONS);WithdrawRunnable w = new WithdrawRunnable(account, AMOUNT, REPETITIONS); Thread t1 = new Thread(d);Thread t2 = new Thread(w);t1.start();t2.start();
강원대학교
class WithdrawRunnable implements Runnable {
public void run() { try { for (int i = 1; i <= count; i+
+) {
account.withdraw(amount); Thread.sleep(DELAY); } } catch (InterruptedException exception) { }}
}
class DepositRunnable implements Runnable {
public void run() { try { for (int i = 1; i <= count;
i++) {
account.deposit(amount); Thread.sleep(DELAY); } } catch (InterruptedExcep-
tion exception) { }}
}
34/70강원대학교
BankAccountpublic void deposit(double amount) { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; }
public void withdraw(double amount) { System.out.print(“Withdrawing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; }
35/70강원대학교
Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Withdrawing 100.0, new balance is -100.0Depositing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Withdrawing 100.0Depositing 100.0, new balance is -100.0, new balance is 100.0Depositing 100.0, new balance is 200.0Withdrawing 100.0, new balance is 100.0Depositing 100.0Withdrawing 100.0, new balance is 0.0, new balance is 200.0Depositing 100.0Withdrawing 100.0, new balance is 300.0, new balance is 100.0Depositing 100.0, new balance is 200.0Withdrawing 100.0, new balance is 100.0
36/70강원대학교
37/70강원대학교
이렇게 한다 해도 해결되지 않음
• Race condition can still occur:
public void deposit(double amount) { balance = balance + amount; System.out.print("Depositing " + amount + ", new balance is " + balance); }
balance = the right-hand-side value
38/70강원대학교
File BankAccountThreadTester.-java
01: /**02: This program runs two threads that deposit and withdraw03: money from the same bank account. 04: */05: public class BankAccountThreadTester06: {07: public static void main(String[] args)08: {09: BankAccount account = new BankAccount();10: final double AMOUNT = 100;11: final int REPETITIONS = 1000;12: 13: DepositRunnable d = new DepositRunnable(14: account, AMOUNT, REPETITIONS);15: WithdrawRunnable w = new WithdrawRunnable(16: account, AMOUNT, REPETITIONS);
39/70강원대학교
File BankAccountThreadTester.-java
17: 18: Thread t1 = new Thread(d);19: Thread t2 = new Thread(w);20: 21: t1.start();22: t2.start();23: }24: }25:
40/70강원대학교
File DepositRunnable.java01: /**02: A deposit runnable makes periodic deposits to a bank // account.03: */04: public class DepositRunnable implements Runnable05: {06: /**07: Constructs a deposit runnable.08: @param anAccount the account into which to deposit // money09: @param anAmount the amount to deposit in each //repetition10: @param aCount the number of repetitions11: */12: public DepositRunnable(BankAccount anAccount, double anAmount,13: int aCount)14: {
41/70강원대학교
File DepositRunnable.java15: account = anAccount;16: amount = anAmount;17: count = aCount;18: }19: 20: public void run()21: {22: try23: {24: for (int i = 1; i <= count; i++)25: {26: account.deposit(amount);27: Thread.sleep(DELAY);28: }29: }30: catch (InterruptedException exception) {}31: }32:
42/70강원대학교
File DepositRunnable.java33: private static final int DELAY = 1; 34: private BankAccount account;35: private double amount;36: private int count;37: }
43/70강원대학교
File WithdrawalRunnable.java01: /**02: A withdraw runnable makes periodic withdrawals from a // bank account.03: */04: public class WithdrawRunnable implements Runnable05: {06: /**07: Constructs a withdraw runnable.08: @param anAccount the account from which to withdraw money09: @param anAmount the amount to deposit in each repetition10: @param aCount the number of repetitions11: */12: public WithdrawRunnable(BankAccount anAccount, double anAmount,13: int aCount)14: {15: account = anAccount;16: amount = anAmount;17: count = aCount;18: }
44/70강원대학교
File WithdrawalRunnable.java19: 20: public void run()21: {22: try23: {24: for (int i = 1; i <= count; i++)25: {26: account.withdraw(amount);27: Thread.sleep(DELAY);28: }29: }30: catch (InterruptedException exception) {}31: }32: 33: private static final int DELAY = 1; 34: private BankAccount account;35: private double amount;36: private int count;37: }
45/70강원대학교
File BankAccount.java01: /**02: A bank account has a balance that can be changed by 03: deposits and withdrawals.04: */05: public class BankAccount06: {07: /**08: Constructs a bank account with a zero balance.09: */10: public BankAccount()11: {12: balance = 0;13: }14: 15: /**16: Deposits money into the bank account.17: @param amount the amount to deposit18: */
46/70강원대학교
File BankAccount.java19: public void deposit(double amount)20: {21: System.out.print("Depositing " + amount);22: double newBalance = balance + amount;23: System.out.println(", new balance is " + newBalance);24: balance = newBalance;25: }26: 27: /**28: Withdraws money from the bank account.29: @param amount the amount to withdraw30: */31: public void withdraw(double amount)32: {33: System.out.print("Withdrawing " + amount);34: double newBalance = balance - amount;35: System.out.println(", new balance is " + newBalance);36: balance = newBalance;37: }
47/70강원대학교
File BankAccount.java38: 39: /**40: Gets the current balance of the bank account.41: @return the current balance42: */43: public double getBalance()44: {45: return balance;46: }47: 48: private double balance;49: }
48/70강원대학교
File BankAccount.javaOutputDepositing 100.0, new balance is 100.0 Withdrawing 100.0, new balance is 0.0 Depositing 100.0, new balance is 100.0 Withdrawing 100.0, new balance is 0.0 . . . Withdrawing 100.0, new balance is 400.0 Depositing 100.0, new balance is 500.0 Withdrawing 100.0, new balance is 400.0 Withdrawing 100.0, new balance is 300.0
49/70강원대학교
객체 접근 동기화(Synchronizing Object Access)
• 두 개 이상이 쓰레드가 하나의 객체에 접근할 때 그 시간을 통제하여 경쟁조건을 해결하는 것
• 어떻게 통제 ?– 한 쓰레드가 단위 작업을 끝내야 쓰레드 스위칭이
일어나도록 함① Synchronized method② Lock
50/70강원대학교
public synchronized void deposit(double amount) { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; }
public synchronized void withdraw(double amount) { System.out.print(“Withdrawing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; }
하나의 BankAccount 객체에 대한 synchronized 메소드 호출들은 서로 섞이지 않는다 .
① Synchronized Method
51/70
Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0Depositing 100.0, new balance is 100.0Withdrawing 100.0, new balance is 0.0
강원대학교
52/70
① Synchronized Method• 하나의 BankAccount 객체에 대한 synchronized method (deposit,
withdraw) 호출은 서로 섞이지 않는다 .• 한 synchronized 메소드가 시작되면 끝날 때까지 다른 synchronized
메소드가 시작되지 않는다 .
강원대학교
double balance
synchronized meth-ods (deposit, with-
draw)
Deposit Thread
Withdraw Thread
deposit withdraw
BankAccount
53/70강원대학교
② Lock• 공유되는 객체에 대응하는 lock 객체를 이용함 .
public class BankAccount { public BankAccount() { balanceLock = new ReentrantLock(); . . . } . . . private Lock balanceLock;}
54/70강원대학교
• 공유 자료를 조작하는 코드를 lock 과 unlock으로 둘러쌈
balanceLock.lock(); Code that manipulates the shared resource balanceLock.unlock();
② Lock
55/70강원대학교
• 쓰레드가 lock 호출에 성공하면 unlock 을 호출할 때까지 lock 을 점유함
• 다른 쓰레드가 lock 을 점유하고 있는 동안 lock을 호출하는 쓰레드는 일시적으로 비활성화됨(deactivated)
• Thread scheduler 는 주기적으로 쓰레드를 활성화시켜 다시 lock 을 점유할 기회를 줌
② Lock
56/70강원대학교
• lock 과 unlock 사이에서 예외가 발생하면 unlock 이 영영 실행되지 못함
• 이런 문제를 해결하기 위해 unlock 을 finally 절에 넣음
② Lock
57/70강원대학교
public void deposit(double amount) { balanceLock.lock(); try { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; } finally { balanceLock.unlock(); } }
* withraw 메소드도 같은 요령으로 처리
② Lock
58/70강원대학교
Deadlock( 교착상태 )• 쓰레드들이 서로 다른 쓰레드의 작업이 마무리
되기를 기다리고 있으나 실제로는 서로 맞물려 더이상 진행하지 못하는 상태
59/70강원대학교
Deadlock( 교착상태 ) 예
public void withdraw(double amount) { balanceChangeLock.lock(); try { while (balance < amount) Wait for the balance to grow . . . } finally { balanceChangeLock.unlock(); }}
• 예금 인출 시 잔고가 모자라면 입금될 때까지 기다리게 하는 경우
이 부분에서 sleep을 호출하면 lock 을 계속 점유하므로 다른 쓰레드가 deposit할 수 없게 됨 – deadlock!
60/70강원대학교
Deadlock( 교착상태 ) 을 방지하는 법
• Condition 객체 사용 • 각 Condition 객체는 특정 Lock 객체에 속함 • 쓰레드가 점유하고 있는 Lock 에 속하는 Condition 에게
await 를 사용하면 쓰레드가 일시적으로 Lock 을 놓게 됨 .• 다른 쓰레드가 그 Condition 에게 signalAll 메소드를
호출하면 await 중인 모든 쓰레드가 await 로부터 복귀함 .
61/70강원대학교
Condition Objectspublic class BankAccount { public BankAccount() { balanceLock = new ReentrantLock();
condition = balanceLock.newCondition(); . . . } . . . private Lock balanceLock; private Condition condition; }
62/70강원대학교
Condition Objectspublic void withdraw(double amount) { balanceLock.lock(); try { while (balance < amount) condition.await(); . . . } finally { balanceLock.unlock(); } }
63/70강원대학교
Condition Objects
public void deposit(double amount) {balanceLock.lock();try {
System.out.print("Depositing " + amount);double newBalance = balance + amount;System.out.println(", new balance is " + newBalance);balance = newBalance;condition.signalAll();
}finally {
balanceLock.unlock();}
}
64/70강원대학교
Condition Objects• 쓰레드가 Condition 에 await 를 호출하면
– 쓰레드가 block 상태로 가면서 일시적으로 Lock 을 놓음으로써 다른 쓰레드가 Lock 을 점유할 기회를 줌
– Block 상태로 간 쓰레드는 다른 쓰레드가 그 condition 에 signalAll 을 호출하거나 inter-rupt 를 걸어 주면 깨어남 .
65/70강원대학교
BankAccountThreadTester.java01: /**02: This program runs four threads that deposit and withdraw03: money from the same bank account. 04: */05: public class BankAccountThreadTester06: {07: public static void main(String[] args)08: {09: BankAccount account = new BankAccount();10: final double AMOUNT = 100;11: final int REPETITIONS = 1000;12: 13: DepositRunnable d1 = new DepositRunnable(14: account, AMOUNT, REPETITIONS);15: WithdrawRunnable w1 = new WithdrawRunnable(16: account, AMOUNT, REPETITIONS);17: DepositRunnable d2 = new DepositRunnable(18: account, AMOUNT, REPETITIONS);
66/70강원대학교
BankAccountThreadTester.java
19: WithdrawRunnable w2 = new WithdrawRunnable(account, 20: AMOUNT, REPETITIONS);21: 22: Thread t1 = new Thread(d1);23: Thread t2 = new Thread(w1);24: Thread t3 = new Thread(d2);25: Thread t4 = new Thread(w2);26: 27: t1.start();28: t2.start();29: t3.start();30: t4.start();31: }32: }33:
67/70강원대학교
File BankAccount.java
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;
public class BankAccount{ private double balance = 0.0; private Lock balanceLock = new ReentrantLock(); private Condition condition = balanceLock.newCondition();
68/70강원대학교
public void deposit(double amount) {balanceLock.lock();try {
System.out.print("Depositing " + amount);double newBalance = balance + amount;System.out.println(", new balance is " + newBalance);balance = newBalance;condition.signalAll();
}finally {
balanceLock.unlock();}
}
69/70강원대학교
public void withdraw(double amount) {balanceLock.lock();try {
while (balance < amount) {try {
condition.await();}catch(InterruptedException e) { }
}System.out.print("Withdrawing " + amount);double newBalance = balance - amount;System.out.println(", new balance is " + newBalance);balance = newBalance;
}finally {
balanceLock.unlock();}
}
70/70강원대학교
/** Gets the current balance of the bank account. @return the current balance */ public double getBalance() { return balance; } }
71/70강원대학교
Output
Depositing 100.0, new balance is 100.0 Withdrawing 100.0, new balance is 0.0 Depositing 100.0, new balance is 100.0 Depositing 100.0, new balance is 200.0 . . . Withdrawing 100.0, new balance is 100.0 Depositing 100.0, new balance is 200.0 Withdrawing 100.0, new balance is 100.0 Withdrawing 100.0, new balance is 0.0