객체지향프로그래밍강원대학교 1/62 제 13 주 멀티쓰레딩 (multi-threading) 제 13...

62
객객객객객객객객객 객객객객객 1/62 객 13 객 객객객객객 (Multi-threading) 제 13 제 제제 제제 제제제제 제제제 제제제 제제제제 제 제제제 제제제제 제제제제 제제 제제 제제제 제제제제 제제제제 제제 제제 제제 제제제제 제제제제제제 제제제제제 제제제 제제 제제제 제제 제제 제제 제제제제제제 제제제제 제제제제 제제 제제

Upload: millicent-hood

Post on 18-Dec-2015

230 views

Category:

Documents


0 download

TRANSCRIPT

객체지향프로그래밍 강원대학교 1/62

제 13 주 멀티쓰레딩(Multi-threading)

제 13 주 목표•여러 쓰레드가 어떻게 병렬도 실행되는 지 이해함•쓰레드를 구현하는 법을 배움•레이스 컨디션과 데드락에 대해 배움•락과 컨디션을 사용함으로써 공유자료가 엉망이 되지 않도록

하는 법을 배움•애니메이션에 스레드를 이용하는 법을 배움

객체지향프로그래밍 강원대학교 2/62

public static void main(String[] args) { final Rectangle box = new Rectangle(5, 10, 20, 30); class Mover implements ActionListener { public void actionPerformed(ActionEvent event) { box.translate(1, 1); System.out.println(box); } } ActionListener listener = new Mover(); final int DELAY = 100; // Milliseconds between timer

ticks Timer t = new Timer(DELAY, listener); t.start(); // 타이머가 별도의 스레드로 실행됨 ! JOptionPane.showMessageDialog(null, "Quit?"); System.out.println("Last box position: " + box); System.exit(0); }

객체지향프로그래밍 강원대학교 3/62

Thread 를 만드는 일반적 방법1. Runnable 인터페이스를 구현하는 클래스를 정의하고

수행할 작업을 run 메소드에 적어준다 .

public interface Runnable{ void run();}

public class MyRunnable implements Runnable { public void run() { // Task statements go here } }

객체지향프로그래밍 강원대학교 4/62

Running a Thread

2. 정의된 클래스 객체를 구성한다 .

3. Runnable 객체를 인자로 삼아 Thread 객체를 구성한다 .

4. Thread 에 start 메소들를 호출한다 .

Runnable r = new MyRunnable();

Thread t = new Thread(r);

t.start();

객체지향프로그래밍 강원대학교 5/62

Example

Thu Dec 28 23:12:03 PST 2004 Hello, 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:06 PST 2004 Hello, World! Thu Dec 28 23:12:07 PST 2004 Hello, World! Thu Dec 28 23:12:08 PST 2004 Hello, World! Thu Dec 28 23:12:09 PST 2004 Hello, World! Thu Dec 28 23:12:10 PST 2004 Hello, World! Thu Dec 28 23:12:11 PST 2004 Hello, World! Thu Dec 28 23:12:12 PST 2004 Hello, World!

• 매 초 현재시각과 "Hello World“ 를 출력하는 프로그램

객체지향프로그래밍 강원대학교 6/62

GreetingRunnable 뼈대

public class GreetingRunnable implements Runnable{ public GreetingRunnable(String aGreeting) { greeting = aGreeting; }

public void run() { // 할 일을 이곳에 적어줌 . . . } // run 메소드에서 이용할 인스턴스 필드 private String greeting; }

객체지향프로그래밍 강원대학교 7/62

GreetingRunnable 의 run 메소드에서 할 일

• 현재시각을 출력 Print a time stamp • 인사말을 출력 Print the greeting • 일 초 동안 기다림 Wait a second

• 현재 날짜와 시간은 Date 객체를 구성함으로써 얻을 수 있다 .

Date now = new Date();

객체지향프로그래밍 강원대학교 8/62

GreetingRunnable 의 run 메소드에서 할 일

• 1 초 기다리기 위해서는 Thread 클래스의 sleep 메소드 호출

• Sleeping thread 는 InterruptedException을 던지는 수가 있음– Catch the exception – Terminate the thread

Thread.sleep(milliseconds)

객체지향프로그래밍 강원대학교 9/62

일반적인 run 메소드 모양

public void run() { try { Task statements } catch (InterruptedException exception) { } Clean up, if necessary }

객체지향프로그래밍 강원대학교 10/62

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: {

객체지향프로그래밍 강원대학교 11/62

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: }

객체지향프로그래밍 강원대학교 12/62

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: Thread t1 = new Thread(r1);13: t1.start();14: }15: }16:

객체지향프로그래밍 강원대학교 13/62

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!");

객체지향프로그래밍 강원대학교 14/62

File GreetingThreadTester.java13: Thread t1 = new Thread(r1);14: Thread t2 = new Thread(r2);15: t1.start();16: t2.start();17: }18: }19:

객체지향프로그래밍 강원대학교 15/62

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!

객체지향프로그래밍 강원대학교 16/62

Thread Scheduler

• Thread scheduler 는 각 쓰레드를 짧은 시간 (time slice) 동안 실행 (activate) 시킨다 .

• 쓰레드 실행 시간에는 작은 변이가 있을 수 있다( 특히 입출력 동작시 ).

• 쓰레드 실행 순서에는 어떤 보장도 없다 .

객체지향프로그래밍 강원대학교 17/62

Threads 종료

• 쓰레드는 run 메소드가 완료되면 종료된다 . • run 메소드가 완료되기 전에 쓰레드를 종료시키려면 그

쓰레드에 interrupt 를 호출한다 .

GreetingRunnable r1 = new GreetingRunnable("Hello, World!");Thread t1 = new Thread(r1);t1.start(); t.interrupt();

객체지향프로그래밍 강원대학교 18/62

Threads 종료

public void run() { for (int i = 1; i <= REPETITIONS && !Thread.interrupted(); i++) { Do work } Clean up }

인터럽트가 걸렸는지 스스로 확인하는 법

interrupt 가 쓰레드를 강제로 종료시키는 것은 아니다 . 쓰레드 자료구조 내의 특정 비트를 세트할 뿐이다 . 쓰레드가 이를 감지하고 스스로 종료해야 한다 .

객체지향프로그래밍 강원대학교 19/62

Threads 종료

• sleep 하고 있는 중에 interrupt 가 걸리면 InterruptedException 이 발생됨

• Interrupt 가 걸린 상태에서 sleep 메소드가 호출되는 경우에도 InterruptedException 이 발생됨

→ run 메소드 내에 sleep 문장이 있는 경우에는 interrupt 가 걸렸는지 일일이 확인할 필요 없이 InterruptedException 발생 여부만을 감시하면 됨

객체지향프로그래밍 강원대학교 20/62

Threads 종료

public void run() { try { for (int i = 1; i <= REPETITIONS; i++) { Do work and sleep } } catch (InterruptedException exception) { 아무것도 하지 않거나 ( 종료 ) 적절한 작업을 함

} Clean up }

객체지향프로그래밍 강원대학교 21/62

public class MyRunnable implements Runnable { public void run() { try { System.out.println(1); Thread.sleep(1000); System.out.println(2); } catch (InterruptedException exception) { System.out.println(3); } System.out.println(4); }}

Thread t = new Thread(new MyRunnable()); t.start(); t.interrupt();

객체지향프로그래밍 강원대학교 22/62

경쟁 조건 (Race Conditions)

• 여러 쓰레드가 하나의 자료를 공유하며 자료를 업데이트 할 때 이 자료가 엉망이 될 수 있다 .

• 예 : 여러 쓰레드가 하나의 은행계좌를 조작할 때

객체지향프로그래밍 강원대학교 23/62

Sample Application

• BankAccount 객체 구성

• 두 개의 쓰레드를 구성 – t1 = DepositRunnable 쓰레드– t2 = WithdrawRunnable 쓰레드– t1 은 일정 시간 간격으로 $100 를 10 번

저축함– t2 는 일정 시간 간격으로 $100 를 10 번

인출함

객체지향프로그래밍 강원대학교 24/62

public void run() { try { for (int i = 1; i <= count; i++) { account.deposit(amount); Thread.sleep(DELAY); } } catch (InterruptedException exception) { }}

DepositRunnable 의 run 메소드

public void deposit(double amount) { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; }

BankAccount 의 deposit 메소드

객체지향프로그래밍 강원대학교 25/62

public void run() { try { for (int i = 1; i <= count; i++) { account.withdraw(amount); Thread.sleep(DELAY); } } catch (InterruptedException exception) { }}

WithdrawRunnable 의

run 메소드

public void withdraw(double amount) { System.out.print("Withdrawing " + amount); double newBalance = balance - amount; System.out.println(", new balance is " + newBalance); balance = newBalance; }

BankAccount 의 withdraw 메소드

객체지향프로그래밍 강원대학교 26/62

Sample Application

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 . . . Withdrawing 100.0, new balance is 0.0

Depositing 100.0Withdrawing 100.0, new balance is 100.0, new balance is -100.0

객체지향프로그래밍 강원대학교 27/62

amount := 100;

newBalance := balance + amount;

--- 스위치

balance := newBalance;

amount := 100;

newBalance := balance - amount;

balance := newBalance;

Deposit thread Withdraw thread

BankAccount 객체는 하나 !인스턴스필드인 balance 도 하나 !지역변수인 newBalance 는 스레드마다 하나씩 !

balance = 0

balance = 100

객체지향프로그래밍 강원대학교 28/62

이렇게 한다 해도 해결되지 않음

public void deposit(double amount) { balance = balance + amount; System.out.print("Depositing " + amount + ", new balance is " + balance); }

붉은 색 문장이 기계적으로는 여러 단계에 걸쳐 실행됨

객체지향프로그래밍 강원대학교 29/62

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);

객체지향프로그래밍 강원대학교 30/62

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:

객체지향프로그래밍 강원대학교 31/62

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: {

객체지향프로그래밍 강원대학교 32/62

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:

객체지향프로그래밍 강원대학교 33/62

File DepositRunnable.java33: private static final int DELAY = 1; 34: private BankAccount account;35: private double amount;36: private int count;37: }

객체지향프로그래밍 강원대학교 34/62

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: }

객체지향프로그래밍 강원대학교 35/62

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: }

객체지향프로그래밍 강원대학교 36/62

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: */

객체지향프로그래밍 강원대학교 37/62

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: }

객체지향프로그래밍 강원대학교 38/62

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: }

객체지향프로그래밍 강원대학교 39/62

File BankAccount.java

OutputDepositing 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

일반적으로는 위와 같이 올바른 출력이 나오지만 잘 못된 출력이 나오는 수가 있음

객체지향프로그래밍 강원대학교 40/62

객체 접근 동기화(Synchronizing Object Access)

• 두 개 이상이 쓰레드가 하나의 객체에 접근할 때 그 시간을 통제하여 경쟁조건을 해결하는 것

• Lock 인터페이스와 Lock 인터페이스를 구현한 클래스를 이용– ReentrantLock: 흔히 쓰이는 Lock 클래스

객체지향프로그래밍 강원대학교 41/62

amount := 100;

newBalance := balance + amount;

--- 스위치

balance := newBalance;

amount := 100;

newBalance := balance - amount;

balance := newBalance;

Deposit thread Withdraw thread

세 문장을 실행하는 중간에 스위칭이 일어나면서 문제 발생 ! 세 문장이 한꺼번에 실행되면 문제가 발생하지 않음

balance = 0

balance = 100

객체지향프로그래밍 강원대학교 42/62

자물쇠를 채움

amount := 100;

newBalance := balance + amount;

balance := newBalance;

자물쇠를 품

자물쇠를 채움

amount := 100;

newBalance := balance - amount;

balance := newBalance;

자물쇠를 품

Deposit thread Withdraw thread

어떤 쓰레드가 자물쇠를 채우면 다른 쓰레드가 그 자물쇠를 사용할 수 없음세 문장을 실행 전에 자물쇠에 lock 을 걸고세 문장의 실행을 마친 후 lock 을 풂 세 문장이 한번에 모두 실행되도록 보장

balance = 0

balance = 0

객체지향프로그래밍 강원대학교 43/62

Synchronizing Object Access

• 통상 공유자료에 접근하는 메소드를 갖는 클래스에 Lock 객체 삽입

public class BankAccount { public BankAccount() { balanceChangeLock = new ReentrantLock(); . . . } . . . private Lock balanceChangeLock;}

ReentrantLock: 흔히 쓰이는 Lock 클래스

객체지향프로그래밍 강원대학교 44/62

Synchronizing Object Access

• 공유 자료에 접근하는 코드를 lock 과 unlock으로 둘러쌈

balanceChangeLock.lock(); Code that manipulates the shared resource balanceChangeLock.unlock();

객체지향프로그래밍 강원대학교 45/62

Synchronizing Object Access

• 쓰레드가 lock 호출에 성공하면 unlock 을 호출할 때까지 Lock 을 점유함

• 다른 쓰레드가 Lock 을 점유하고 있는 동안 lock을 호출하는 쓰레드는 일시적으로 비활성화됨(deactivated)

• Thread scheduler 는 주기적으로 쓰레드를 활성화시켜 다시 Lock 을 점유할 기회를 줌

객체지향프로그래밍 강원대학교 46/62

Synchronizing Object Access

• lock 과 unlock 사이에서 예외가 발생하면 unlock 이 영영 실행되지 못함

• 이런 문제를 해결하기 위해 unlock 을 finally 절에 넣음

객체지향프로그래밍 강원대학교 47/62

Synchronizing Object Access

public void deposit(double amount) { balanceChangeLock.lock(); try { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; } finally { balanceChangeLock.unlock(); } }

* withraw 메소드도 같은 요령으로 처리

객체지향프로그래밍 강원대학교 48/62

Deadlock( 교착상태 )

• 쓰레드들이 다른 쓰레드의 작업이 마무리 되기를 기다리고 있으나 실제로는 서로 맞물려 더 이상 진행하지 못하는 상태

객체지향프로그래밍 강원대학교 49/62

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!

객체지향프로그래밍 강원대학교 50/62

Deadlock( 교착상태 ) 을 방지하는 법

• Condition 객체 사용 • Condition 객체는 특정 Lock 객체와 연계됨• Condition 을 사용하면 쓰레드가 일시적으로

Lock 을 놓았다가 나중에 다시 점유하게 됨

객체지향프로그래밍 강원대학교 51/62

Condition Objects

public void withdraw(double amount) { balanceChangeLock.lock(); try { while (balance < amount) sufficientFundsCondition.await(); . . . } finally { balanceChangeLock.unlock(); } }

객체지향프로그래밍 강원대학교 52/62

Condition Objects

public class BankAccount { public BankAccount() { balanceChangeLock = new ReentrantLock(); sufficientFundsCondition = balanceChangeLock.newCondition(); . . . } . . . private Lock balanceChangeLock; private Condition sufficientFundsCondition; }

객체지향프로그래밍 강원대학교 53/62

Condition Objects• 쓰레드가 await 를 호출하면

– 쓰레드가 block 상태로 감– 이 쓰레드에 의해 점유된 자물쇠의 lock 이

일시적으로 풀림 ( 다른 쓰레드가 Lock 객체를 점유할 기회를 줌 )

– Block 상태로 간 쓰레드는 unblock 될 때까지 thread scheduler 에 의해 activate 되지 않음 (time slice 를 배정받지 못함 )

– 나중에 쓰레드가 unblock 되면 자동으로 자물쇠를 다시 점유하게 됨

객체지향프로그래밍 강원대학교 54/62

Condition Objects

• Block 된 쓰레드를 unblock 하려면 다른 쓰레드가 condition 에 signalAll 메소드를 호출해 주어야 함

• signalAll 은 그 condition 으로 block 된 모든 쓰레드를 unblock 해 줌

sufficientFundsCondition.signalAll();

객체지향프로그래밍 강원대학교 55/62

Condition Objectspublic void deposit(double amount) { balanceChangeLock.lock(); try { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; sufficientFundsCondition.signalAll(); } finally { balanceChangeLock.unlock(); } }

객체지향프로그래밍 강원대학교 56/62

BankAccountThreadTester.java

01: /**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);

객체지향프로그래밍 강원대학교 57/62

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:

객체지향프로그래밍 강원대학교 58/62

File BankAccount.javaimport java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;

/** 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; balanceChangeLock = new ReentrantLock(); sufficientFundsCondition = balanceChangeLock.newCondition(); }

객체지향프로그래밍 강원대학교 59/62

/** Deposits money into the bank account. @param amount the amount to deposit */ public void deposit(double amount) { balanceChangeLock.lock(); try { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; sufficientFundsCondition.signalAll(); } finally { balanceChangeLock.unlock(); } }

객체지향프로그래밍 강원대학교 60/62

/** Withdraws money from the bank account. @param amount the amount to withdraw */ public void withdraw(double amount) throws InterruptedException { balanceChangeLock.lock(); try { while (balance < amount) sufficientFundsCondition.await(); System.out.print("Withdrawing " + amount); double newBalance = balance - amount; System.out.println(", new balance is " + newBalance); balance = newBalance; } finally { balanceChangeLock.unlock(); } }

객체지향프로그래밍 강원대학교 61/62

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

객체지향프로그래밍 강원대학교 62/62

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