Professional Documents
Culture Documents
Java Ch9 Thread
Java Ch9 Thread
faa)
ในบทที่เกานี้เราจะมาดูกันถึงเรื่องของการประมวลผลขอมูลหลาย ๆ ตัวในเวลาพรอม ๆ กัน
(ไลเลี่ยกัน) โดยไมเกิดปญหาที่ขัดแยงกันระหวางโปรแกรม (หรือ โปรแกรมยอย) ซึ่งเรา
สามารถทําไดดว ยการเรียกใช thread ของ Java
หลังจากจบบทเรียนนี้แลวผูอานจะไดทราบถึง
o ความหมายของ thread
o วงจรชีวิตของ thread
o การสรางและใช thread
o การ synchronize threads
o ตัวอยางการใช thread
1
ดูขอมูลเพิ่มเติมไดจาก หนังสือที่เกี่ยวกับระบบปฏิบัติการ (Operating System)
เริ่มตนการเขียนโปรแกรมดวย Java
Thread 1 Thread 2
1. A virtual CPU
2. code ที่ CPU ทําการประมวลผลอยู
3. data ที่ code ใชในการประมวลผล
CPU
CODE DATA
276
บทที่ 9: Thread
new
โปรแกรมเริ่มการทํางาน
ของ thread
Thread ตองรอ
waiting บางอยางใหเกิดขั้น executing Thread สิ้นสุด terminating
การทํางาน
1: /**
2: Simple Thread demonstration
3: */
4:
5: import java.util.Random;
6: import static java.lang.System.out;
7:
8: class Thread1Demo extends Thread {
9: private int count = 5;
10: private int sleepTime;
11: private static int threadCount = 0;
12: private static Random time;
13:
14: Thread1Demo(String name) {
15: super(name + ++threadCount);
16: time = new Random();
17: start();
18: }
19:
20: public void run() {
21: while(true) {
22: sleepTime = time.nextInt(1000);
23: out.printf("I'm %s, going to sleep for %d milliseconds%n",
getName(), sleepTime);
24: //maximum sleep time 1 second
25: try {
26: sleep(sleepTime);
27: }
28: catch(InterruptedException e) {
29: //do nothing
30: }
31: out.printf("%s done sleeping%n", getName());
277
เริ่มตนการเขียนโปรแกรมดวย Java
super(name + ++threadCount);
start();
Thread#1
Thread#2
Thread#3
start()
start()
start()
run()
run()
run()
Run จนกวา
count จะเทากับ
0 ซึ่งอาจเปนเวลา Run จนกวา
เทาใดก็ได ขึ้นอยู count จะเทากับ
กับ 0 ซึ่งอาจเปนเวลา Run จนกวา
nextInt(1000) เทาใดก็ได ขึ้นอยู count จะเทากับ
กับ 0 ซึ่งอาจเปนเวลา
nextInt(1000) เทาใดก็ได ขึ้นอยู
กับ
nextInt(1000)
278
บทที่ 9: Thread
279
เริ่มตนการเขียนโปรแกรมดวย Java
1: /**
2: Simple Thread demonstration
3: */
4:
5: import java.util.Random;
6: import java.util.concurrent.Executors;
7: import java.util.concurrent.ExecutorService;
8: import static java.lang.System.out;
9:
10: class Thread2Demo implements Runnable {
11: private int count = 5;
12: private int sleepTime;
13: private static int threadCount = 0;
14: private String name;
15: private static Random time;
16:
17: Thread2Demo(String name) {
18: this.name = name + ++threadCount;
19: time = new Random();
20: }
21:
22: public void run() {
23: while(true) {
24: sleepTime = time.nextInt(1000);
25: out.printf("I'm %s, going to sleep for %d milliseconds%n",
this.name, sleepTime);
26: //maximum sleep time 1 second
27: try {
28: Thread.sleep(sleepTime);
29: }
30: catch(InterruptedException e) {
31: //do nothing
32: }
33: out.printf("%s done sleeping%n", this.name);
34: if(--count == 0) break;
35: }
36: out.printf("%s FINISHED.%n", this.name.toUpperCase());
37: }
38:
39: public static void main(String[] args) {
40: //creating 3 threads
41: Thread2Demo []thread = new Thread2Demo[3];
42: for(int i = 0; i < 3; i++) {
43: thread[i] = new Thread2Demo("Thread#");
44: }
45: ExecutorService exec = Executors.newFixedThreadPool(3);
46: exec.execute(thread[0]);
47: exec.execute(thread[1]);
48: exec.execute(thread[2]);
49:
50: exec.shutdown();
51:
52: out.println("Done executing in main.");
53: }
54: }
280
บทที่ 9: Thread
new Thread(thread[0]).start();
new Thread(thread[1]).start();
new Thread(thread[2]).start();
281
เริ่มตนการเขียนโปรแกรมดวย Java
1: /**
2: Thread priority
3: */
4:
5: import java.util.Random;
6: import java.util.concurrent.Executors;
7: import java.util.concurrent.ExecutorService;
8: import static java.lang.System.out;
9:
10: class ThreadPriority extends Thread {
11: private int count = 5;
12: private int sleepTime;
13: private static int threadCount = 0;
14: private String name;
15: private static Random time;
16:
17: ThreadPriority(String name, int priority) {
18: this.name = name + ++threadCount;
19: setPriority(priority);
20: time = new Random();
21: }
22:
23: public void run() {
24: while(true) {
25: sleepTime = time.nextInt(1000);
26: out.printf("I'm %s, with a priority of %d%n",
this.name, getPriority());
27: //maximum sleep time 1 second
28: try {
29: Thread.sleep(sleepTime);
30: }
31: catch(InterruptedException e) {
32: //do nothing
33: }
34: out.printf("%s done sleeping%n", this.name);
35: if(--count == 0) break;
36: }
37: out.printf("%s FINISHED.%n", this.name.toUpperCase());
38: }
39:
40: public static void main(String[] args) {
41: //creating 3 threads with different priority
42: ThreadPriority []thread = new ThreadPriority[3];
43: for(int i = 0; i < 3; i++) {
44: thread[i] = new ThreadPriority("Thread#", i+3);
45: }
46:
47: //using Executor to manage threads
48: ExecutorService exec = Executors.newFixedThreadPool(3);
49:
50: //start threads
51: exec.execute(thread[0]);
52: exec.execute(thread[1]);
53: exec.execute(thread[2]);
282
บทที่ 9: Thread
54:
55: exec.shutdown(); //terminate threads
56: }
Code ในบรรทัดที่ 19 เปนการกําหนด priority ของ thread สวน code ในบรรทัดที่ 26 เปนการ
เรียกดู priority ของ thread ขอควรระวังในการใช setPriority() ตองไมกําหนดให priority มีคา
สูงเกิน MAX_PRIORITY หรือต่ํากวา MIN_PRIORITY ผลลัพธที่เราไดจากการ run คือ
2
หนังสือหลาย ๆ เลมเรียกกระบวนการนี้วา Mutual Exclusion
283
เริ่มตนการเขียนโปรแกรมดวย Java
1: /**
1: /**
2: unsynchronized bank account
3: */
4:
5: import static java.lang.System.out;
6:
7: class UnSyncAccount {
8: //a shared balance
9: private double balance;
10:
11: //setup initial balance
12: public UnSyncAccount(double balance) {
13: this.balance = balance;
14: out.printf("%15c%15c%,15.2f%n", ' ', ' ', balance);
15: }
16:
17: //return a balance
18: public double getBalance() {
19: return balance;
20: }
21:
22: //deposit amount into account
23: public void deposit(double amount) {
24: out.printf("%s deposits %.2f%n",
25: Thread.currentThread(), amount);
26: balance += amount;
27: out.printf("%,15.2f%15c%,15.2f%n", amount,
28: ' ', getBalance());
29: }
30:
31: //withdraw some amount
32: public void withdraw(double amount) {
33: //do nothing when amount is not enough
34: if(amount < balance)
284
บทที่ 9: Thread
35: return;
36: out.printf("%s withdraws %.2f%n",
37: Thread.currentThread(), amount);
1: /**
2: Program to deposit into a shared account
3: */
4:
5: import static java.lang.System.out;
6: import java.util.Random;
7:
8: class Deposit implements Runnable {
9: //shared saving account
10: private UnSyncAccount saving;
11: //amount to deposit
12: private double amount;
13: //waiting time
14: private Random sleepTime = new Random();
15:
16: //set the shared account
17: public Deposit(UnSyncAccount saving, double amount) {
18: this.saving = saving;
19: this.amount = amount;
20: }
21:
22: //deposit amount 5 times
23: public void run() {
24: try {
25: for(int i = 0; i < 5; i++) {
26: saving.deposit(amount);
27: Thread.sleep(sleepTime.nextInt(2000));
28: }
29: }
30: catch(InterruptedException ie) {
31: ie.printStackTrace();
32: }
33: }
34: }
1: /**
2: Program to withdraw from a shared account
3: */
4:
5: import static java.lang.System.out;
6: import java.util.Random;
7:
8: class Withdraw implements Runnable {
9: //shared account
10: private UnSyncAccount saving;
11: //amount to withdraw
12: private double amount;
13: //busy time
14: private Random sleepTime = new Random();
15:
16: //set a shared account
17: public Withdraw(UnSyncAccount saving, double amount) {
18: this.saving = saving;
19: this.amount = amount;
20: }
21:
22: //withdraw amount five times
23: public void run() {
24: try {
25: for(int i = 0; i < 5; i++) {
285
เริ่มตนการเขียนโปรแกรมดวย Java
26: saving.withdraw(amount);
27: Thread.sleep(sleepTime.nextInt(2000));
28: }
balance += amount;
286
บทที่ 9: Thread
Thread 2 sleeps
load 1000 1000
Thread 1 sleeps
load 1000 1000
Thread 2 sleeps
store 1500 1500
1. ใช locks
2. ใช synchronized
try {
balance += amount;
out.printf("%,15.2f%15c%,15.2f%n", amount, ' ', getBalance());
287
เริ่มตนการเขียนโปรแกรมดวย Java
}
finally {
//unlock this account
try {
//if balance is too low, do nothing
if(balance < amount)
return;
//reset the balance
balance -= amount;
out.printf("%15c%,15.2f%,15.2f%n", ' ', amount, getBalance());
}
finally {
//unlock this account
account.unlock();
}
}
288
บทที่ 9: Thread
try {
//if balance is too low or other
//thread is busy with balance, we wait...
funds.signalAll();
[และเราก็ตองเรียกใชคําสั่งเดียวกันหลังจากที่เรานําเงินเขาสูบัญชีดวยเหมือนกัน เพราะฉะนั้น
deposit() ก็จะกลายเปน]
try {
//if other thread is busy with balance, we wait...
while(occupied) {
out.printf("waiting for withdrawal...%n");
funds.await();
}
balance += amount;
out.printf("%,15.2f%15c%,15.2f%n", amount, ' ', getBalance());
occupied = true;
//signal threads waiting for the account
funds.signalAll();
}
catch(InterruptedException ie) {
ie.printStackTrace();
}
finally {
//unlock this account
account.unlock();
}
}
289
เริ่มตนการเขียนโปรแกรมดวย Java
account.lock(); account.lock();
while(occupied) { while(balance < amount ||
… !occupied) {
funds.await(); …
} funds.await();
}
CRITICAL
UPDATE BALANCE UPDATE BALANCE
SECTION
occupied = true; occupied = false;
funds.signalAll(); funds.signalAll();
account.unlock(); account.unlock();
1: /**
2: Synchronization on a bank account
3: */
4:
5: import java.util.concurrent.Executors;
6: import java.util.concurrent.ExecutorService;
7: import static java.lang.System.out;
8:
9: class SyncAccountTest {
10: public static void main(String[] args) {
11: //create pool of threads
12: ExecutorService app = Executors.newFixedThreadPool(4);
13:
14: //print header
15: out.printf("%15s%15s%15s%n", "Deposit", "Withdrawal", "Balance");
16:
17: //set up shared account with initial balance
18: SyncAccount sharedAccount = new SyncAccount(0);
19:
20: Deposit p1 = new Deposit(sharedAccount, 100.0);
21: Withdraw p2 = new Withdraw(sharedAccount, 1000.0);
22: Withdraw p3 = new Withdraw(sharedAccount, 100.0);
23: Deposit p4 = new Deposit(sharedAccount, 1000.0);
24:
25: //perform deposit and withdrawal simultaneously
26: try {
27: app.execute(p1);
28: app.execute(p2);
29: app.execute(p3);
30: app.execute(p4);
31: }
32: catch(Exception ex) {
33: ex.printStackTrace();
290
บทที่ 9: Thread
34: }
35: //stop synchronization
36: app.shutdown();
ผูอานควรสังเกตถึงผลลัพธที่ไดวาถูกตองตามขั้นตอนหรือไม ซึ่งสามารถตรวจสอบไดดวยการ
run หลาย ๆ ครั้ง แนนอนวาผลลัพธที่ไดจะไมเหมือนกัน แตสิ่งที่เหมือนกันคือ balance จะตอง
เปนศูนยเสมอเมื่อการทํางานสิ้นสุดลง
291
เริ่มตนการเขียนโปรแกรมดวย Java
someLock.lock();
try {
while(!(ok to proceed))
CRITICAL SECTION
condition.signalAll();
}
catch() {
…//some exception might be thrown here
}
finally {
//must unlock the lock even though exception is thrown
someLock.unlock();
}
1: /**
2: Account using keyword synchronized
3: BankAccount is shared by Account1 and Account2
4: */
5:
292
บทที่ 9: Thread
synchronized(. . .) {
//code … ที่มีการเรียกใช wait() และ notify() หรือ notifyAll()
}
293
เริ่มตนการเขียนโปรแกรมดวย Java
1: /**
2: Program to access a shared account
3: */
4:
5: import static java.lang.System.out;
6: import java.util.Random;
7:
8: class Account1 extends Thread {
9: //shared saving account
10: private BankAccount saving;
11: //amount to deposit
12: private double amount;
13: //waiting time
14: private Random sleepTime = new Random();
15:
16: //set the shared account
17: public Account1(BankAccount saving, double amount) {
18: this.saving = saving;
19: this.amount = amount;
20: }
21:
22: //deposit random amounts 5 times
23: public void run() {
24: try {
25: for(int i = 0; i < 5; i++) {
26: saving.deposit(amount);
27: Thread.sleep(sleepTime.nextInt(2000));
28: }
29: }
30: catch(InterruptedException ie) {
31: ie.printStackTrace();
32: }
33: }
34: }
1: /**
2: Program to access a shared account
3: */
4:
5: import static java.lang.System.out;
6: import java.util.Random;
7:
8: class Account2 extends Thread {
9: //shared account
10: private BankAccount saving;
11: //amount to withdraw
12: private double amount;
13: //busy time
14: private Random sleepTime = new Random();
294
บทที่ 9: Thread
15:
16: //set a shared account
17: public Account2(BankAccount saving, double amount) {
1: /**
2: Synchronization on a bank account
3: */
4:
5: import static java.lang.System.out;
6:
7: class BankAccountTest {
8: public static void main(String[] args) {
9: out.printf("%15s%15s%15s%n", "Deposit", "Withdrawal", "Balance");
10: //set up a shared account
11: BankAccount sharedAccount = new BankAccount(0);
12:
13: //create 2 accounts
14: Account1 acc1 = new Account1(sharedAccount, 100.0);
15: Account2 acc2 = new Account2(sharedAccount, 100.0);
16: Account1 acc3 = new Account1(sharedAccount, 100.0);
17: Account2 acc4 = new Account2(sharedAccount, 100.0);
18:
19: //start running the two processes
20: acc1.start();
21: acc2.start();
22: acc3.start();
23: acc4.start();
24: }
25: }
295
เริ่มตนการเขียนโปรแกรมดวย Java
9.6.3 Deadlock
account.lock();
try {
while(balance < amount) {
out.printf("waiting for deposit...%n");
funds.await();
}
//reset the balance
balance -= amount;
out.printf("%15c%,15.2f%,15.2f%n", ' ', amount, getBalance());
//signal threads waiting for the account
funds.signalAll();
}
catch(InterruptedException ie) {
ie.printStackTrace();
}
finally {
//unlock this account
account.unlock();
}
296
บทที่ 9: Thread
สรุป
แบบฝกหัด
4. การแกปญหาในเรื่องของการฝากและถอนเงินของเราที่แสดงไวในบทนี้ ยังไมสมบรูณ
ทีเดียวนัก กลาวคือ การถอนเงินจะทําไมไดถามีเงินไมครบในบัญชี โดยเรากําหนดให
โปรแกรมยุติการทํางานทันที ถาเหตุการณดงั กลาวเกิดขึ้น จงปรับปรุงโปรแกรมดังกลาวให
สลับการถอนเงินมาเปนการฝากเงิน ถามีเงินในบัญชีนอยกวาที่ตองถอน
class BankAccountTest1 {
public static void main(String[] args) {
out.printf("%15s%15s%15s%n", "Deposit",
"Withdrawal", "Balance");
//set up a shared account
BankAccount sharedAccount = new BankAccount(10000);
//create accounts
Account1 []acc1 = new Account1[3];
Account2 []acc2 = new Account2[3];
for(int i = 0; i < 3; i++) {
acc1[i] = new Account1(sharedAccount);
acc1[i].setPriority((int)(Math.random()*10 + 1));
acc1[i].start();
acc2[i].start();
}
}
}
297
เริ่มตนการเขียนโปรแกรมดวย Java
298