Lập trình Java căn bản - Chương 9 THREADS

25 4 0
Lập trình Java căn bản - Chương 9 THREADS

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Quá trình (process) là trạng thái tức thời của một chương trình đang chạy trên máy tính. Nó bao gồm bộ nhớ cần thiết để chạy chương trình (không gian địa chỉ của quá trình) và khả năng kiểm soát hiện trạng của bộ xử lý trong quá trình thực thi chương trình (tiến trình điều khiển của quá trình).

Chương 9- THREADS Mục tiêu Sau chương bạn Định nghĩa luồng (thread) Hiểu đa luồng gì? Biết cách tạo luồng Java Hiểu nhu cầu ñồng (synchronize) luồng Biết cách dùng wait() notify() ñể giao tiếp luồng Nội dung 9.1- Ơn tập 9.2- Luồng đa luồng 9.3- Luồng Java 9.4- Trạng thái luồng 9.5- Lập trình luồng Java 9.6- Độ ưu tiên luồng 9.7- Đồng luồng 9.8- Deadlock 9.9- Cơ chế Chờ-nhận biết 9.10- Tóm tắt 9.1- Ơn tập Gói AWT cung cấp lớp cho ta xây dựng GUI lớp sử dụng hỗ trợ phụ thuộc platform LỚp Graphics Graphics2D gói AWT cho ta cơng cụ vẽ hình xuất file ảnh Lớp Applet JApplet cung cấp khả tạo ứng dụng nhỏ Java nhúng vào trang Web chúng ñược thực thi Browser appletviewer cho phép chạy Java applet mà khơng cần đến Browser 9.2- Luồng đa luồng Luồng- thread: Một dịng lệnh mà CPU phải thực thi Các hệ ñiều hành cho phép nhiều luồng ñược thực thi ñồng thời Chúng ta ñã quen với việc mở nhiều ứng dụng lần làm việc với máy tính Nhiều ứng dụng ñược nạp Như – Một luồng chuỗi lệnh nằm nhớ ( chương trình nạp) – application thơng thường thực thi luồng – Trong application có nhiều luồng Thí dụ chuyển động 10 ñối tượng hành trò chơi 10 luồng Kỹ thuật đa luồng Với máy có m CPU chạy m luồng Mỗi CPU chạy luồng Hiệu Với máy có m CPU chạy n luồng với n>> m Mỗi CPU chạy n/m luồng Với CPU chạy ñồng thời k luồng với k>1 Các luồng ñược quản lý hàng ñợi, luồng ñược cấp phát thời gian mà CPU thực thi ti (cơ chế time-slicing – phân chia tài nguyên thời gian) Luồng ñỉnh hàng ñợi ñược lấy ñể thực thi trước, sau ti thời gian mình, luồng đưa vào cuối hàng ñợi CPU lấy luồng Với máy có CPU mà lại chạy k luồng Hiệu suất chương trình Lợi ích đa luồng Tăng hiệu suất sử dụng CPU: Phần lớn thời gian thực thi ứng dụng chờ ñợi nhập liệu từ user hiệu suất sử dụng CPU chưa hiệu qủa Tạo ñược ñồng đối tượng: Thí dụ trị chơi, nhân vật chuyển động Trong trang Web, tạo ñược ñồng thời ñường diềm (marquee) tiêu ñề ñộng (banner, chữ,ảnh chạy), vừa hiển thị ñồng hồ, vừa phát nhạc, vừa chơi game, vừa hoạt ảnh (animated images),… Trang Web thật bắt mắt (eye-catching) quyến rũ (captivating) Quản lý ñược thời gian ứng dụng thi online, thời gian chơi trò chơi 9.3- Luồng Java Main thread - luồng : luồng chứa luồng khác Đây luồng cho Java Application hành (mức toàn application) Child thread - luồng : luồng ñược tạo từ luồng khác Khi application thực thi, main thread ñược chạy, gặp phát biểu phát sinh luồng con, luồng ñược khởi tạo Vào thời điểm luồng kết thúc, application kết thúc Java cung cấp lớp Thread mô tả luồng gói java.lang 9.4- Trạng thái luồng Sinh (Born) new Thread() Hết thời gian ngủ Sẵn sàng ( Ready ) notify() notify() start() Đang chờ ( Waiting ) Ngủ lúc ( Sleeping ) Bị tạm hoãn ( Suspended ) Bị khóa ( Blocked ) run() wait() wait() sleep() Đang chạy ( Running ) stop() hay chạy xong Hành vi ñể buộc luồng chuyển trạng thái chờ biến cố xuất/nhập Đã chết ( Dead ) Trạng thái luồng Một luồng sau sinh (born) khơng chạy mà sẵn sàng (ready) chạy Chỉ phương thức start() ñược gọi luồng thực thi (chạy code phương thức run()) Luồng thực thi bị tạm ngưng phương thức sleep() thời khoảng lại ready sau ñáo hạn thời gian Luồng ñang ngủ không sử dụng tài nguyên CPU Khi nhiều luồng ñược thực thi, có luồng giữ tài nguyên mà không nhả làm cho luồng khác khơng dùng tài ngun (đói tài ngun) Để tránh tình này, Java cung cấp chế WaitNotify(đợi-nhận biết) chế trình bày mục sau Phương thức wait() giúp ñưa luồng vào trạng thái chờ Trạng thái luồng Khi luồng bị tạm ngưng hay bị treo, luồng rơi vào trạng thái tạm hoãn (suspended) Phương thức suspend()- version cũ/ wait() Java dùng cho mục đích Khi suspended thread ñược mang thực thi tiếp, trạng thái luồng resumed Phương thức resume() – version cũ/ notify() Java ñ c dùng cho m c ñích Khi luồng chờ biến cố xuất/nhập liệu Luồng rơi vào trạng thái blocked Khi luồng thực thi xong phương thức run() hay gặp phương thức stop(), ta nói luồng chết (dead) 9.5- Lập trình luồng Java Cách 1: Xây dựng lớp lớp java.lang.Thread, override hành vi run() ñể phù hợp với mục đích tốn Cách 2: Xây dựng lớp có thực interface Runnable – Khơng cần import java.lang gói – java.lang.Thread lớp Java xây dựng sẵn ñã thực interface Runnable – Interface java.lang.Runnable có method run() – Tham khảo thêm gói java.lange Tham khảo lớp Thread 9.5.1- Tạo luồng lớp lớp Thread class MyThread extends Thread { // liệu + hành vi lớp public void run() { // thực code phụ thuộc toán } } 9.5.2- Tạo luồng với interface Runnable class MyThread implements Runnable { // liệu + hành vi lớp public void run() { // thực code phụ thuộc toán } } 9.5.3- Khởi tạo thực thi luồng MyThread t = new MyThread(); // tạo luồng t.start(); // thị cho luồng thực thi Hành vi start() tự ñộng gọi hành vi run() 9.5.4- Thread Constructors Thread () Thread (Runnable target) Thread (Runnable target, String Name) Thread (String Name) Thread (ThreadGroup group, Runnable target) Thread (ThreadGroup group, Runnable target, String Name) Thread (ThreadGroup group, Runnable target, String Name, long stacksize) Thread (ThreadGroup group, String Name) target : luồng cha name: tên gọi luồng ñược tạo 9.5.5- Hai loại luồng Luồng Daemon: luồng hệ thống, chạy mức (background- chạy ngầm), luồng cung cấp dịch vụ cho luồng khác Các trình JVM tồn luồng daemon tồn JVM có luồng daemon luồng “garbage collection” Luồng user tạo 9.5.6- Methods thơng dụng lớp Thread Method Mục đích static int enumerate (Thread Sao chép luồng ñang hoạt ñộng [] t) (active) vào mảng từ nhóm luồng nhóm chúng final String getName() Lấy tên luồng final boolean isAlive() Kiểm tra luồng sống hay không? final void setName( String Đặt tên cho luồng NewName) final void join () throws Chờ luồng chết interruptedException public final isDaemon() boolean Kiểm tra xem luồng có phải luồng daemon void setDaemon(boolean on) on=true : luồng daemon on=false : luồng user 9.5.6- Methods thơng dụng lớp Thread Method Mục đích static void sleep (long Trì hỗn luồng thời gian milisec) void start() thực thi luồng static int activeCount() Đếm số luồng ñang hoạt ñộng static void yield() Tạm dừng luồng hành ñể luồng khác tiếp tục thực thi 10 Minh họa tạo luồng với lớp Thread // Thread1.java – Minh họa tạo luồng với lớp Thread class Thread1 extends Thread { public void Create() // tạo luồng luồng cha hành { Thread t = new Thread (this); t.start(); } public void run() // override hành vi run() { System.out.println("This is child thread."); } public static void main (String args[]) { System.out.println("This is main thread."); Thread1 t= new Thread1(); t.Create(); // tạo luồng Kết qủa: } This is main thread } This is child thread Pres any key to continue Minh họa tạo luồng với lớp interface Runnable class Thread2 implements Runnable Khi xây dựng luồng interface Runable, phải { public void Create() khai báo ñối tượng { Thread t = new Thread(this); Thread gọi hành vi start() ñể hành vi gọi t.start(); run() } public void run() // implement the run () method { System.out.println("This is child thread."); } public static void main (String args[]) { System.out.println("This is main thread."); Thread2 t= new Thread2(); t.Create(); } Kết qủa: } This is main thread This is child thread Pres any key to continue 11 MInh họa số methods Thread class Thread3 implements Runnable // Thread3.java { Thread t1,t2; Thread3() { t1= new Thread(this); Kết qủa luồng t1.start(); // t1 is an user-defined thread tích cực : luồng gom t2= new Thread(this); rác, luồng mẹ t2.setDaemon(true); // t2 is a daemon thread } luồng t1,t2 public void run() { int n= Thread.activeCount(); // Đếm số luồng ñang tích cực JVM System.out.println("Number of active threads:" + n); String t1Name = t1.getName(); // lấy tên luồng String t2Name = t2.getName(); System.out.println("Name of t1 thread:" + t1Name); Kết System.out.println("Name of t2 thread:" + t2Name); This is main thread System.out.println("Is t1 thread a daemon? :" + t1.isDaemon()); Number of active threads:4 System.out.println("Is t2 thread a daemon? :" + t2.isDaemon()); Name of t1 thread:Thread-1 System.out.println("Is t1 thread alive? :" + t1.isAlive()); Name of t2 thread:Thread-2 System.out.println("Is t2 thread alive? :" + t2.isAlive()); Is t1 thread a daemon? :false } Is t2 thread a daemon? :true public static void main (String args[]) Is t1 thread alive? :true { System.out.println("This is main thread."); Is t2 thread alive? :false Thread3 t= new Thread3(); Press any key to continue } } Tên mặc ñịnh luồng Thread-n, với n số thứ tự luồng ñược tạo Minh họa trạng thaí luồng class Thread4 extends Thread// // Thread4.java { Thread t; Thread4() { t= new Thread(this); System.out.println("t thread is born and ready."); t.start(); } public void run() { try { System.out.println("t thread is running."); t.sleep(5000); System.out.println("t is awaked and running again after secs."); } catch( InterruptedException e) Dòng xuất sau giây so với dòng trước { System.out.println("thread is interrupted!"); } } public static void main (String args[]) t thread is born and ready t thread is running { new Thread4(); t is awaked and running again after secs } Press any key to continue } 12 9.6- Độ ưu tiên luồng Các luồng chia sẻ thời gian CPU Luồng cuối hàng ñợi lâu ñược CPU thực thi Có nhu cầu thay đổi độ ưu tiên luồng Java cung cấp mơ tả độ ưu tiên luồng (các ñộ ưu tiên khác dùng số nguyên từ 10) NORM_PRIORITY : mang trị MAX_PRIORITY : mang trị 10 MIN_PRIORITY : mang trị Độ ưu tiên mặc ñịnh luồng NORMAL_PRIORITY Luồng có độ ưu tiên với luồng cha (do ñặc ñiểm thừa kế) Thao tác với ñộ ưu tiên luồng final void setPriority( int newPriority) final int getPriority() Như vậy, ñiều kiện ñể luồng khơng thực thi: Luồng khơng có độ ưu tiên cao ñể dành lấy thời gian CPU Luồng bị cưỡng ngủ hành vi sleep() Luồng bị chờ hành vi wait() Luồng bị tường minh nhận hành vi yield() Luồng bị khóa chờ I/O 13 Minh họa ñộ ưu tiên luồng class Thread5 extends Thread// Thread4.java { public void run() { Thread Child = new Thread(this); Child.setName("Child thread"); System.out.println("Name of current thread:" + Thread.currentThread().getName()); System.out.println("Piority of current thread:" + Thread.currentThread().getPriority()); System.out.println("Name of child:" + Name of current thread:Parent thread Child.getName()); Piority of current thread:5 System.out.println("Priority of child:" + Name of child:Child thread Child.getPriority()); Priority of child:5 } Press any key to continue public static void main (String args[]) { Thread5 t = new Thread5(); Nếu main(), thêm dòng t.start(); t.setPriority (8); trước dịng t.start(); t.setName("Parent thread"); ta có kết qủa thay } } 9.7- Đồng luồng Tình huống: Có hai luồng t1, t2 truy xuất ñối tượng liệu biến m t1 muốn đọc biến m cịn t2 muốn ghi biến m liệu mà t1 đọc khơng qn Nếu t2 ghi m trước t1 đọc sau t1 đọc liệu qn thời điểm Cần có chế ñể cho phép luồng ñược truy xuất liệu chung (shared data) thời ñiểm Kỹ thuật gọi “ĐỒNG BỘ HÓA – SYNCHRONIZATION” 14 Kỹ thuật đồng hóa Tạo ñối tượng quản lý ñồng thao tác liệu luồng cách thực thi hộ tác vụ luồng lần cho luồng từ khóa synchronized Mọi đối tượng luồng ñều ñược ñối tượng quản lý quan sát (MONITOR) cách cho đối tượng luồng có liệu đối tượng monitor thay phải làm tác vụ nhờ đối tượng monitor làm hộ biến boolean ñể nhận biết ñã có luồng thực thi Luồng chiếu cố gọi luồng có monitor Minh họa ñồng luồng MONITOR Chương trình sau xuất số 10,11, 12 hình, số ñược luồng thực thi // Monitor1.java – Lớp làm nhiệm vụ xuất hộ số num class Monitor1 { synchronized void Display (int num) { System.out.println("Output " + num + " - done."); try { Thread.sleep(500); // current thread sleep 1/2 sec } catch (InterruptedException e) { System.out.println ("Thread is interrupted!"); } } } Từ khóa synchronized khai báo có quản lý việc đồng luồng 15 Minh họa ñồng luồng MONITOR class OutNum implements Runnable // luồng { Monitor1 monitor; // Luồng có liệu monitor int number; // liệu cần xuất Thread t; // hành vi xuất n với Monitor1 có tên moni OutNum(Monitor1 moni, int n ) { monitor= moni; number = n; t = new Thread(this); t.start(); } // luồng chạy, số number ñược xuất monitor public void run() { monitor.Display(number); } } Minh họa ñồng luồng MONITOR class Synchro // lớp chương trình luồng có trị { public static void main (String args[]) khác 10,11, 12 { Monitor1 monitor = new Monitor1(); có chung int num = 10; monitor OutNum Obj1 = new OutNum(monitor,num++); Ba luồng OutNum Obj2 = new OutNum(monitor,num++); ñơ OutNum Obj3 = new OutNum(monitor,num++); // wait for threads to end try Output 10 - done { Obj1.t.join(); Output 11 - done Obj2.t.join(); Output 12 - done Obj3.t.join(); Press any key to continue } catch(InterruptedException e) { System.out.println ("Thread was interrupted!"); } } } 16 Kỹ thuật ñồng luồng theo khối Đồng khối tác vụ Người lập trình khơng muốn dùng synchronized method ñể ñồng truy xuất ñến ñối tượng Các lớp ñược cung cấp thư viện hay “một đó” cung cấp – lớp xây dựng- nên khơng thể thêm từ khóa synchonized vào method Kỹ thuật ñồng luồng theo khối Cú pháp ñồng khối synchronized (Object) { } Buộc phải có { } dù có phát biểu 17 Minh họa đồng khối Chương trình sau viết lại chương trình trước, bỏ qua từ khóa synchronized lớp Monitor1 ( ñây gọi lớp Monitor2) class Monitor2 // Monitor2.java { void Display (int num) { System.out.println("Output " + num + " - done."); try { Thread.sleep(500); // current thread sleap 1/2 sec } catch (InterruptedException e) { System.out.println ("Thread is interrupted!"); } } } Minh họa ñồng khối class Synchro { public static void main (String args[]) { Monitor2 monitor = new Monitor2(); int num = 10; OutNum Obj1 = new OutNum(monitor,num++); OutNum Obj2 = new OutNum(monitor,num++); OutNum Obj3 = new OutNum(monitor,num++); // wait for threads to end try { Obj1.t.join(); Obj2.t.join(); Obj3.t.join(); } catch(InterruptedException e) { System.out.println ("Thread was interrupted!"); } } } 18 Minh họa ñồng khối class OutNum implements Runnable { Monitor2 monitor; int number; Thread t; OutNum(Monitor2 moni, int n ) { monitor= moni; number = n; t = new Thread(this); t.start(); } public void run() { synchronized (monitor) { monitor.Display(number); } } } Minh họa ñồng khối 19 9.8- Deadlock Deadlock – tình bế tắc, đóng băng- xẩy luồng chờ tài nguyên (monitor) hình thành chu trình Deadlock xẩy Minh họa: DeadlockDemo.java Giải thích DeadlockDemo class ứng dụng có luồng :Luồng t1 đối tượng d1, luồng t2 ñối tượng d2 Monitor t1 lại d2 monitor t2 lại d1 (tréo nhau) Cả luồng gọi hành vi synchronized run() ngủ 300 mili giây.Vì chia sẻ thời gian CPU nên t1 ngủ trước t2 ngủ sau (xem phương thức run()) Khi t1 thức dậy (wake up), phương thức Synchro() ñối tượng monitor d2 (chứa luồng t2) ñược gọi luồng t2 ñang ngủ nên phương thức chưa thể thực thi Khi t2 thức dậy (wake up), phương thức Synchro() ñối tượng monitor d1 (chứa luồng t1) ñược gọi luồng t1 ñang ngủ nên phương thức chưa thể thực thi Như chương trình đóng băng (blocked) khơng làm 20 9.9- Cơ chế chờ- nhận biết Java cung cấp sẵn chế giao tiếp liên qúa trình (inter-process mechanism) để luồng gọi (yêu cầu nhau) sử dụng final methods lớp Object: wait() , notify() , notifyAll() Như lớp sử dụng chúng phương thức gọi synchronized methods Cơ chế wait-notify Phương thức wait() : Luồng nhả monitor ñể ñi vào trạng thái sleep cho ñến luồng khác vào monitor gọi phương thức notify Phương thức notify() : Luồng thức dậy (wake up) nhận biết (notify) luồng thứ ñã gọi wait() Phương thức notifyAll() : Đánh thức tất luồng ñang ngủ ñể chúng biết luồng hành ñã gọi phương thức wait() Khi tất luồng ñang ngủ thức dậy, luồng có ưu tiên cao nắm giữ monitor thực thi 21 Chú ý ñối với phương thức wait Luồng gọi phương thức wait() nhả CPU, không dùng CPU Luồng gọi phương thức wait() nhả monitor, thơi khơng khóa (lock) monitor Luồng gọi phương thức wait() ñược ñưa vào danh sách hàng ñợi monitor (monitor waiting pool) Chú ý ñối với phương thức notify Một luồng ñang ngủ ñược ñưa khỏi monitor waiting pool ñi vào trạng thái ready Luồng vừa thức giấc (notify) phải giành lại monitor khóa monitor lại khơng cho luồng khác chiếm ñể luồng ñược thực thi 22 Chú ý ñối với phương thức notifyAll Luồng ñang thực thi cảnh báo cho tất luồng ngủ “Tơi ñi ngủ ñây, bạn dậy ñể làm việc” Luồng ñầu danh sách monitor waiting pool ñược vào trạng thái ready Bài toán triết gia ăn tối với đũa 23 9.10- Tóm tắt Luồng biện pháp chia cơng việc thành đơn vị cụ thể (concrete) nên dùng để thay vịng lặp Lập trình đa luồng làm tăng hiệu suất CPU hệ thống “bận rộn” Tuy nhiên hiệu suất ứng dụng lại bị giảm ñang kể (chậm ba bốn lần tác vụ đồng hóa), qúa trình biên dịch chậm trình biên dịch phải tính tốn chế quản lý luồng Do ứng dụng địi hỏi yếu tố hiệu suất thời gian quan trọng, nên tránh sử dụng kỹ thuật đồng hóa Nhiều lập trình viên khơng thích lập trình đa luồng mà dùng lập trình lập trình đơn luồng để tăng hiệu suất ứng dụng Java cung cấp kỹ thuật lập trình đa luồng lớp Thread interface Runnable Khi ứng dụng Java thực thi, có luồng chạy luồng (main thread) Luồng quan trọng (1) Đây luồng sinh luồng con, (2) Quản lý việc kết thúc ứng dụng luồng main kết thúc tất luồng kết thúc Tóm tắt Hiện thực luồng cách: Hiện thực lớp lớp Thread, override phương thức run() lớp Khai báo lớp mà ta xây dựng implement interface Runnable ñịnh nghĩa phương thức run() Mỗi java thread có độ ưu tiên từ (MIN) ñến 10 (MAX) với trị mặc ñịnh JVM khơng thay đổi độ ưu tiên luồng Có contructor lớp Thread constructor thường dùng: Thread() Thread(String TênLuồng), Thread(ĐốiTượngChứa) Các phương thức Thread.suspend(), Thread.resume(), Thread.stop() khơng cịn dùng kể từ Java Luồng daemon luồng chạy ngầm nhằm cung cấp dịch vụ cho luồng khác Nếu muốn luồng daemon, dùng public final void setDeamon (boolean) kiểm tra luồng có daemon hay khơng, dùng public final boolean isDaemon() 24 Tóm tắt Dữ liệu bị quán(hư hỏng) có luồng truy xuất liệu thời điểm Đồng 1q trình bảo đảm tài nguyên (dữ liệu, file,…) ñược luồng sử dụng thời điểm Tuy nhiên, chi phí cho việc lại làm giảm hiệu suất thời gian ứng dụng xuống 3, lần Phương thức wait() làm luồng vào trạng th ngủ Phương thức notify() ñánh thức luồng thứ danh sách luồng ñang chờ ñối tượng monitor Phương thức notifyAll() ñánh thức tất luồng danh sách luồng ñang chờ ñối tượng monitor Deadlock xẩy luồng có phụ thuộc vịng cặp đối tượng quản lý việc đồng (synchronized object) Xin cám ơn 25 ... dung 9. 1- Ơn tập 9. 2- Luồng đa luồng 9. 3- Luồng Java 9. 4- Trạng thái luồng 9. 5- Lập trình luồng Java 9. 6- Độ ưu tiên luồng 9. 7- Đồng luồng 9. 8- Deadlock 9. 9- Cơ chế Chờ-nhận biết 9. 1 0- Tóm tắt 9. 1-. .. khơng thích lập trình đa luồng mà dùng lập trình lập trình đơn luồng để tăng hiệu suất ứng dụng Java cung cấp kỹ thuật lập trình đa luồng lớp Thread interface Runnable Khi ứng dụng Java thực thi,... phương thức chưa thể thực thi Như chương trình đóng băng (blocked) khơng làm ñược 20 9. 9- Cơ chế ch? ?- nhận biết Java cung cấp sẵn chế giao tiếp liên qúa trình (inter-process mechanism) để luồng gọi

Ngày đăng: 21/05/2021, 14:58

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan