Khỏi nim thread ệ

Một phần của tài liệu Bài giảng về Java (Trang 137)

I.1 Khỏi ni m:ệ

Thread – lu ng ch m t đ n v chồ ỉ ộ ơ ị ương trỡnh cú th tỏch kh i cỏc ph n khỏc c aể ỏ ầ ủ chương trỡnh đ th c hi n song song v i cỏc ph n khỏc t ng kho ng th i gian ho c trongể ự ệ ớ ầ ở ừ ả ờ ặ toàn b quỏ trỡnh nú th c hi n. ộ ự ệ

Trong m i chỗ ương trỡnh Java, cú m t lu ng chớnh độ ồ ược b t đ u b ng vi c g i hàmắ ầ ằ ệ ọ main(), cỏc lu ng khỏc cú th phỏt sinh t lu ng chớnh này. Cỏc cõu l nh trong hàm main() n uồ ể ừ ồ ệ ế khụng được đ a vào m t lu ng riờng thỡ s đư ộ ồ ẽ ược th c hi n tu n t .ự ệ ầ ự

I.2. L p Threadớ

L p Thread trong gúi java.lang cú m t s constructor:ớ ộ ố Public Thread (<tờn thread>)

Public thread(): Khi này thread s cú tờn là Thread_1, Thread_2,….ẽ

Cỏc cụng vi c c a m t thread đệ ủ ộ ược đ t trong phặ ương th c run(). Phứ ương th c này cúứ th để ược khai bỏo ch ng trong l p khai bỏo k th a Thread ho c khai bỏo cài đ t giao di nồ ớ ế ừ ặ ặ ệ Runable.

Ngườ ậi l p trỡnh b t đ u m t thread b ng cỏc g i phắ ầ ộ ằ ọ ương th c start(), phứ ương th cứ start() sau đú s g i run(). Sau khi start() th c hi n xong, nú tr v đi u khi n cho chẽ ọ ự ệ ả ề ề ể ương trỡnh g i nú. Do đú, chọ ương trỡnh g i nú và thread đọ ược th c hi n m t cỏch đ ng th i.ự ệ ộ ồ ờ

• Phương th c start() s nộm ra m t ng o i l IllegalThreadStateException n uứ ẽ ộ ạ ệ ế thread c n b t đ u đó b t đ u r i.ầ ắ ầ ắ ầ ồ

• Phương th c tĩnh sleep c a Thread đứ ủ ược g i v i m t tham s xỏc đ nh r ngọ ớ ộ ố ị ằ m t thread đang ch y s d ng l i trong bao lõu theo đ n v ph n nghỡn giõy.ộ ạ ẽ ừ ạ ơ ị ầ Trong khi m t thread “sleep”, nú s khụng tiờu t n tài nguyờn CPU và threadộ ẽ ố khỏc cú th ch y.ể ạ

• Phương th c interrupt() đứ ược g i đ đ ng t m t thread. Phọ ể ể ắ ộ ương th c này trứ ả v true n u ng t thành cụng. Phề ế ắ ương th c isInterrupted() dựng đ ki m tra xemứ ể ể thread cú b ng t hay khụng.ị ắ

• Phương th c isAlive() tr v true n u start() đó đứ ả ề ế ược g i và phọ ương th c run()ứ v n đang th c hi n.ẫ ự ệ

• Phương th c setName() đ t tờn cho m t thread, getName() l y tờn m t thread.ứ ặ ộ ấ ộ Phương th c toString() tr v tờn phứ ả ề ương th c, đ u tiờn và nhúm c a thread.ứ ộ ư ủ • Phương th c static currentThread() tr v tham chi u t i thread hi n hành đangứ ả ề ế ớ ệ

th c hi n.ự ệ

• Phương th c joint đ i (ứ ợ wait) m t ph n h i c a m t thụng đi p độ ả ổ ủ ộ ệ ược g i điử trước khi th c hi n thread.ự ệ

I.3 Cỏc bước đ t o m t threadể ạ

Sau đõy là cỏc bước đ n gi n đ th c hi n m t nhi m v trong m t thread riờng:ơ ả ể ự ệ ộ ệ ụ ộ 1. Khai bỏo m t l p cú cài đ t giao di n Runable v i phộ ớ ặ ệ ớ ương th c run() đứ ược đ nhị nghĩa:

class MyRunnable implements Runnable {

public void run() {

// code th c hi nự ệ }

}

2. T o m t đ i tạ ộ ố ượng c a l pủ ớ Runnable r = new MyRunnable();

3. T o m t đ i tạ ộ ố ượng Thread t đ i từ ố ượng Runable trờn: Thread t = new Thread(r);

4. G i phọ ương th c start()ứ t.start();

M t thread cũng cú th độ ể ượ ạc t o ra b ng cỏch xõy d ng m t l p con c a l p Thread:ằ ự ộ ớ ủ ớ class MyThread extends Thread

{

public void run() {

// code c a threadủ }

}

Sau đú ta cũng làm theo cỏc bước 2,3 và 4 đ th c hi n thread.ể ự ệ

II. Cỏc tr ng thỏi c a thread.ạ

• Tr ng thỏi born: Khi thread ch a g i start().ạ ư ọ

• Tr ng thỏi ready: Khi phạ ương th c start() đứ ược g i.ọ

• Tr ng thỏi running: M t Thread tr ng thỏi ready cú quy n u tiờn cao nh t sạ ộ ở ạ ề ư ấ ẽ được chuy n sang tr ng thỏi này.ể ạ

• Tr ng thỏi dead: Khi m t Thread ng ng ho c hoàn thành nhi m v c a nú.ạ ộ ư ặ ệ ụ ủ Ngoài ra, m t thread running cũng cú th b ch n (blocked) trong cỏc thao tỏc vào ra.ộ ể ị ặ Lỳc này nú cũng khụng s d ng tài nguyờn CPU.ử ụ

• Tr ng thỏi sleep: Khi Thread g i phạ ọ ương th c sleep. N u đang tr ng thỏi sleepứ ế ở ạ mà g i phọ ương th c interrupt(), tread s thoỏt kh i tr ng thỏi sleep và chuy nứ ẽ ỏ ạ ể sang tr ng thỏi ready.ạ

Sau đõy là s đ tr ng thỏi c a m t thread.ơ ồ ạ ủ ộ

Khi m t thread đang ch y g i phộ ạ ọ ương th c wait(), thread s r i vào m t tr ng thỏi waitứ ẽ ơ ộ ạ đ đ i m t đ i tể ợ ộ ố ượng mà nú đó g i.ọ

III. Cỏc thu c tớnh c a threadộ III.1 Đ u tiờn c a threadộ ư

M i Thread cú m t đ u tiờn. M c đ nh thỡ thread th a k đ u tiờn t thread chaỗ ộ ộ ư ặ ị ừ ế ộ ư ừ c a nú- là thread đó g i nú. Ta cú th tăng ho c gi m đ u tiờn c a b t kỳ thread nào v iủ ọ ể ặ ả ộ ư ủ ấ ớ phương th c setPriority() b ng m t giỏ tr n m gi a MIN_PRIORITY(1) và MAX_PRIORITYứ ằ ộ ị ằ ữ (10).

Cỏc thread cú đ u tiờn càng cao thỡ kh năng th c hi n càng cao.ộ ư ả ự ệ

III.2 Nhúm thread

Cỏc thread cú th để ược đ a vào cựng m t nhúm đ cú th đ ng th i làm vi c v i cư ộ ể ể ồ ờ ệ ớ ả nhúm thread này.

Khai bỏo m t nhúm Thread:ộ String groupName = . . .;

ThreadGroup g = new ThreadGroup(groupName)

Sau đú, v i m i thread đớ ỗ ượ ạc t o ra ta dựng constructor cú khai bỏo nhúm thread: Thread t = new Thread(g, threadName);

Đ ki m tra xem cú thread nào trong nhúm g cũn ho t đ ng khụng, ta dựng phể ể ạ ộ ương th c:ứ

g. activeCount();

Đ ng t t t c cỏc thread trong nhúm g ta g i:ể ắ ấ ả ọ g.interrupt();

III.3 Qu n lý cỏc ngo i l c a threadả ạ ệ ủ

Phương th c run() khụng th nộm ra m t ngo i l đứ ể ộ ạ ệ ược ki m soỏt mà b k t thỳc b iể ị ế ở m t ngo i l khụng ki m soỏt độ ạ ệ ể ược m i khi cú l i. Khụng cú m nh đ catch nào đỗ ỗ ệ ề ược th cự

hi n mà thay vào đú, trệ ước khi thread b dead, ngo i l này s đị ạ ệ ẽ ược g i cho m t b x lýử ộ ộ ử ngo i l khụng đạ ệ ược ki m soỏt.ể

Bộ xử lý này ph i thu c m t l p cú cài đ t giao di nả ộ ộ ớ ặ ệ Thread.UncaughtExceptionHandler ch v i 1 phỉ ớ ương th c:ứ

void uncaughtException(Thread t, Throwable e);

T phiờn b n Java 1.5, ta cú th cài b x lý ngo i l cho b t c thread nào b ngừ ả ể ộ ử ạ ệ ấ ứ ằ phương th c: setUncaughtExceptionHandler(). Mgoaif ra ta cú th cài b x lý ngo i l m cứ ể ộ ử ạ ệ ặ đ nh cho t t c cỏc thread b ng cỏch g i phị ấ ả ằ ọ ương th c setDefaultUncaughtExceptionHandlerứ c a l p Thread.ủ ớ

N u khụng cài b x lý ngo i l cho m t thread thỡ m c đ nh là null. Tuy nhiờn, cỏcế ộ ử ạ ệ ộ ặ ị thread riờng l i ph thu c vào b x lý c a nhúm thread ch a nú. Khi này, phạ ụ ộ ộ ử ủ ứ ương th cứ uncaughtException s làm cỏc vi c sau:ẽ ệ

1- N u nhúm thread cú cài đ t uncaughtException thỡ phế ặ ương th c đú đứ ược g i.ọ

2- Ngượ ạc l i, n u phế ương th c Thread.getDefaultExceptionHandler tr v m t b xứ ả ề ộ ộ ử lý khụng ph i là null thỡ b x lý này đả ộ ử ược g i.ọ

3- N u là null, n u Throwable là m t đ i tế ế ộ ố ượng c a TheadDead, khụng cú gỡ x y ra.ủ ả 4- N u khụng, tờn c a thread và stack trace đế ủ ược g i t i System.err và đ a ra màn hỡnh.ử ớ ư

IV. Đi u khi n cỏc threadề

Sau khi đó kh i đ ng đở ộ ược m t thread r i, v n đ ti p theo s là đi u khi n thread.ộ ồ ấ ề ế ẽ ề ể

IV.1 Interrupt m t threadộ

Khi s d ng phử ụ ương th c Thread.sleep(int) thỡ chứ ương trỡnh thường ph i b t cỏc ngo iả ắ ạ l đ x lý. Lý do là thread b d ng l i trong m t kho ng th i gian lõu và trong kho ng th iệ ể ử ị ừ ạ ộ ả ờ ả ờ gian đú nú khụng th t đỏnh th c nú để ự ứ ược. Tuy nhiờn, n u m t thread c n ph i đế ộ ầ ả ược đỏnh th c s m h n, ta cú th ng t nú dựng phứ ớ ơ ể ắ ương th c interrupt().ứ

public class SleepyHead extends Thread {

// Phương th c đứ ược ch y khi thread kh i đ ng l n đ uạ ở ộ ầ ầ public void run()

{

System.out.println ("Thread đang ng . Hóy đỏnh th c nú");ủ ứ try { // Ng trong 8 ti ngủ ế Thread.sleep( 1000 * 60 * 60 * 8 ); System.out.println ("Đú là m t gi c ng tr a");ộ ấ ủ ư }

catch (InterruptedException ie) {

System.err.println ("Ch m i đỉ ớ ược h n 5 phỳt thụi....");ơ }

}

// Phương th c main t o và b t đ u threadứ ạ ắ ầ public static void main(String args[]) throws java.io.IOException

{

// T o m t threadạ ộ

Thread sleepy = new SleepyHead(); // b t đ u threadắ ầ

sleepy.start();

// Nh c ngắ ười dựng đ d ng threadể ừ

System.out.println ("Nh n Enter đ ng ng thread");ấ ể ư System.in.read();

// Ng t threadắ sleepy.interrupt(); }}

Cỏch th c hi n đõy là g i m t thụng đi p t m t thread khỏc đ đỏnh th c m tự ệ ở ử ộ ệ ừ ộ ể ứ ộ thread đang ng . đõy, thread chớnh- hàm main- s đ i cho ngủ Ở ẽ ợ ười dựng n enter, sau đú g iấ ử m t thụng đi p ng t t i thread đang ng .ộ ệ ắ ớ ủ

IV.2 D ng m t threadừ

Đụi khi ta mu n m t thread d ng l i trố ộ ừ ạ ước khi nhi m v c a nú hoàn thành. M tệ ụ ủ ộ thread (g i là thread đi u khi n) cú th g i m t thụng đi p d ng t i m t thread khỏc b ngọ ề ể ể ử ộ ệ ừ ớ ộ ằ vi c g i phệ ọ ương th c Thread.stop(). Đi u này yờu c u thread đi u khi n ph i gi m t thamứ ề ầ ề ể ả ữ ộ chi u t i thread mu n d ng.ế ớ ố ừ

public class StopMe extends Thread {

// Phương th c đứ ược th c hi n khi thread kh i đ ng l n đ uự ệ ở ộ ầ ầ public void run()

{

int count = 1;

System.out.println ("Thread đ m!");ế for (;;)

{

// In ra bi n count và tăng giỏ tr cho núế ị System.out.print (count++ + " "); // Ng n a giõyủ ử

try { Thread.sleep(500); } catch (InterruptedException ie) {} }}

// phương th c mainứ

public static void main(String args[]) throws java.io.IOException {

// T o và b t đ u threadạ ắ ầ

Thread counter = new StopMe(); counter.start(); // Nh c ngắ ười dựng System.out.println ("Nh n Enter đ d ng đ m");ấ ể ừ ế System.in.read(); // D ng threadừ counter.stop(); 142

}}

IV.3 T m d ng và ph c h i m t threadạ

Cỏc phương th c suspend() dựng đ t m d ng m t thread trong khi resume() dựng đứ ể ạ ừ ộ ể ti p t c m t thread đó b suspend. Tuy nhiờn s d ng cỏc thread này r t hay gõy ra tỡnh tr ngế ụ ộ ị ử ụ ấ ạ deadlock do thread b suspend đang chi m gi m t tài nguyờn và khụng gi i phúng trong khiị ế ữ ộ ả nhi u thread khỏc cú th đang đ i s d ng tài nguyờn đú.ề ể ợ ử ụ

IV.4 Gi i phúng th i gian cho CPUả

Khi m t thread r i vào tr ng thỏi đ i m t s ki n x y ra ho c đi vào m t vựng móộ ơ ạ ợ ộ ự ệ ả ặ ộ l nh mà n u gi i phúng th i gian cho CPU s nõng cao hi u qu c a h th ng. Trong trệ ế ả ờ ẽ ệ ả ủ ệ ố ường h p này, thread nờn gi i phúng th i gian h th ng h n là dựng sleep() đ ngh trong th i gianợ ả ờ ệ ố ơ ể ỉ ờ dài. Đ làm đi u này ta dựng phể ề ương th c static yield() c a Thread đ gi i phúng th i gianứ ủ ể ả ờ CPU cho thread hi n th i. Ta khụng th gi i phúng th i gian CPU c a b t kỳ thread nào màệ ờ ể ả ờ ủ ấ ch đ i v i thread hi n th i.ỉ ố ớ ệ ờ

IV.5 Đ i m t thread k t thỳc cụng vi cợ ế

Đụi khi ta c n đ i cho m t thread k t thỳc m t cụng vi c nào đú nh g i m t phầ ợ ộ ế ộ ệ ư ọ ộ ương th c hay đ c m t thu c tớnh thành ph n,…Ta dựng phứ ọ ộ ộ ầ ương th c isAlive() đ xỏc đ nh threadứ ể ị cũn ch y khụng. Tuy nhiờn, n u thạ ế ường xuyờn dựng phương th c này đ ki m tra sau đú dựngứ ể ể sleep() ho c yield() thỡ hi u qu s d ng CPU s r t th p. M t cỏch hi u qu là g i phặ ệ ả ử ụ ẽ ấ ấ ộ ệ ả ọ ương th c joint() đ đ i m t thread k t thỳc cụng vi c.ứ ể ợ ộ ế ệ

public class WaitForDeath extends Thread {

// Phương th c run()ứ public void run() {

System.out.println ("thread chu n b ngh ....");ẩ ị ỉ // Ngh trong 5 giõyỉ

try {

Thread.sleep(5000); }

catch (InterruptedException ie) {} }

// phương th c mainứ

public static void main(String args[]) throws java.lang.InterruptedException

{

// T o threadạ

Thread dying = new WaitForDeath(); dying.start();

// Nh c userắ

System.out.println ("Đ i cho thread k t thỳc");ợ ế dying.join();

V. Đ ng b threadồ

Trong h u h t cỏc chầ ế ương trỡnh đa lu ng, cỏc thread cú th c n ph i truy c p đ n cựngồ ể ầ ả ậ ế m t đ i tộ ố ượng. Đi u gỡ x y ra n u c hai thread cựng truy c p đ n đ i tề ả ế ả ậ ế ố ượng và làm thay đ iổ thu c tớnh đ i tộ ố ượng. K t qu cú th là cỏc thread b nh hế ả ể ị ả ưởng l n nhau và khụng đ t đẫ ạ ược k t qu mong mu n. Tỡnh tr ng này g i là “đua tranh”.ế ả ố ạ ọ

V.1 Tỡnh tr ng “đua tranh”ạ

Trong ph n ti p theo, chỳng ta mụ ph ng m t ngõn hàng cú r t nhi u tài kho n khỏchầ ế ỏ ộ ấ ề ả hàng. Chỳng ta th thi t k m t chử ế ế ộ ương trỡnh đ chuy n ti n ng u nhiờn gi a cỏc tài kho n.ể ể ề ẫ ữ ả M i tài kho n cú m t thread riờng. M i giao d ch th c hi n vi c chuy n ti n t account sangỗ ả ộ ỗ ị ự ệ ệ ể ề ừ m t account ng u nhiờn khỏc.ộ ẫ

Ta cú m t class Bank v i phộ ớ ương th c transfer đ chuy n ti n. N u account chuy nứ ể ể ề ế ể khụng đ ti n, giao d ch k t thỳc ngay. ủ ề ị ế

public void transfer(int from, int to, double amount) {

System.out.print(Thread.currentThread()); accounts[from] -= amount;

System.out.printf(" %10.2f from %d to %d", amount, from, to); accounts[to] += amount;

System.out.printf(" S d : %10.2f%n", getTotalBalance());ố ư }

Sau đõy là đo n code cho class transferRunnable:ạ class TransferRunnable implements Runnable {

. . .

public void run() {

try {

int toAccount = (int) (bank.size() * Math.random()); double amount = maxAmount * Math.random(); bank.transfer(fromAccount, toAccount, amount); Thread.sleep((int) (DELAY * Math.random())); }

catch(InterruptedException e) {} }

}

Khi chương trỡnh ch y, ta khụng bi t đạ ế ược trong m i tài kho n cũn bao nhiờu ti nỗ ả ề nh ng t ng s ti n c a t t c cỏc tài kho n là khụng đ i. Chư ổ ố ề ủ ấ ả ả ổ ương trỡnh trờn ch y và khụngạ bao gi d ng l i, ta ph i n Ctrl + C đ d ng nú.ờ ừ ạ ả ấ ể ừ

Tuy nhiờn, trong m t s tỡnh hu ng chộ ố ố ương trỡnh trờn cú th gõy l i và in ra t ng sể ỗ ổ ố ti n khỏc nhau, đú là khi cú nhi u h n m t tài kho n cựng chuy n ti n đ n m t tài kho nề ề ơ ộ ả ể ề ế ộ ả khỏc, t c là cựng th c hi n cõu l nh:ứ ự ệ ệ

account[to] += amount;

Gi s đõy là m t hành vi đ n v (atomic- hành vi ch chi m m t chu kỳ th c hi n l nhả ử ộ ơ ị ỉ ế ộ ự ệ ệ c a CPU), khi đú m i thread s th c hi n phộp tớnh này m t cỏch tu n t mà khụng gõy nhủ ỗ ẽ ự ệ ộ ầ ự ả hưởng vỡ trong m t th i đi m, CPU cũng ch ph c v độ ờ ể ỉ ụ ụ ược cho m t thread.ộ

Tuy nhiờn, phộp tớnh này l i khụng ph i là atomic, cụng vi c cú th ph i làm là:ạ ả ệ ể ả 1- Load giỏ tr account[to] vào thanh ghiị

2- C ng v i accountộ ớ

3- Load k t qu ngế ả ược tr l i cho account[to]ả ạ

Gi s cú 2 thread là thread_1 và thread_2 cựng th c hi n đ n dũng l nh này. Thread_1ả ử ự ệ ế ệ th c hi n xong bự ệ ước 1 và 2 thỡ b ng t, sau đú thread_2 s th c hi n cõu l nh trờn v i đ y đị ắ ẽ ự ệ ệ ớ ầ ủ 3 bướ ức t c là account[to] đó b thay đ i giỏ tr . Ti p theo, thread_1 th c d y và làm ti p bị ổ ị ế ứ ậ ế ước 3, account[to] lỳc này đó ghi đố giỏ tr do thread_2 c p nh t. Đi u này d n t i vi c t ng s ti nị ậ ậ ề ẫ ớ ệ ổ ố ề b thay đ i, ph n ti n do thread_2 chuy n cho account[to] đó b m t.ị ổ ầ ề ể ị ấ

V.2 Khúa đ i tố ượng

Trong vớ d trờn, n u ta đ m b o r ng phụ ế ả ả ằ ương th c transfer() đứ ược th c hi n thànhự ệ cụng trước khi thread b ng t thỡ s khụng cú v n đ gỡ x y ra. Cú nghĩa là, trong m t th iị ắ ẽ ấ ề ả ộ ờ đi m s ch cú m t thread để ẽ ỉ ộ ược truy c p vào m t đo n mó l nh nào đú.ậ ộ ạ ệ

T phiờn b n Java 5.0 cú h tr hai c ch đ b o v m t kh i l nh kh i s truy c pừ ả ỗ ợ ơ ế ể ả ệ ộ ố ệ ỏ ự ậ đ ng th i. Cỏc phiờn b n trồ ờ ả ước c a Java s d ng t khúa synchronized, Java 5.0 gi i thi uủ ử ụ ừ ớ ệ thờm l p ReentrantLock cho m c đớch này.ớ ụ

C u trỳc đo n l nh căn b n đ s d ng c ch này là:ấ ạ ệ ả ể ử ụ ơ ế myLock.lock(); // đ i tố ượng ReentrantLock

try { //Đo n l nh c n b o vạ ệ ầ ả ệ

Một phần của tài liệu Bài giảng về Java (Trang 137)

Tải bản đầy đủ (PDF)

(151 trang)