Bài giảng Lập trình Java - Chương 4: Lập trình đa luồng trong Java
Lập trình đơn luồng
(Single Threaded Programming)
Chương trình biên dịch thành mã máy. Khối mã này được CPU
xử lý tuần tự.
Xử lý đơn luồng đơn giản, dễ kiểm soát, dễ dàng biết được
lỗi phát sinh ở đâu.
Thời gian xử lý các câu lệnh khác nhau, nhưng một câu lệnh
chưa thực thi xong thì các câu lệnh khác không được chạy
không hợp lý.Lập trình đa luồng
(Multi Threaded Programming)
Nhiều câu lệnh, nhiệm vụ được thực hiện đồng thời,
cùng một không gian bộ nhớ, và các luồng có thể
cho phép chia sẻ các đối tượng dữ liệu để cùng xử lý.Giới thiệu HĐH đa nhiệm
Hệ điều hành đa nhiệm cổ điển:
Đơn vị cơ bản sử dụng CPU là process.
Process là đoạn chương trình độc lập đã được nạp vào bộ nhớ.
Mỗi process thi hành một ứng dụng riêng.
Mỗi process có một không gian địa chỉ và một không gian
trạng thái riêng.
Các process liên lạc với nhau thông qua cơ chế điều phối của
HĐH.
Tóm tắt nội dung tài liệu: Bài giảng Lập trình Java - Chương 4: Lập trình đa luồng trong Java
LẬP TRÌNH ĐA LUỒNG (MULTITHREAD) TRONG JAVA Nội dung Giới thiệu về đơn luồng và đa luồng Tạo và quản lý luồng trong java Sử dụng Thread và Runnable Vòng đời Thread Độ ưu tiên, Đồng bộ hóa Ví dụ minh họa Lập trình đơn luồng (Single Threaded Programming) Chương trình biên dịch thành mã máy. Khối mã này được CPU xử lý tuần tự. Xử lý đơn luồng đơn giản, dễ kiểm soát, dễ dàng biết được lỗi phát sinh ở đâu. Thời gian xử lý các câu lệnh khác nhau, nhưng một câu lệnh chưa thực thi xong thì các câu lệnh khác không được chạy không hợp lý. Lập trình đa luồng (Multi Threaded Programming) Nhiều câu lệnh, nhiệm vụ được thực hiện đồng thời, cùng một không gian bộ nhớ, và các luồng có thể cho phép chia sẻ các đối tượng dữ liệu để cùng xử lý. Giới thiệu HĐH đa nhiệm Hệ điều hành đa nhiệm cổ điển: Đơn vị cơ bản sử dụng CPU là process. Process là đoạn chương trình độc lập đã được nạp vào bộ nhớ. Mỗi process thi hành một ứng dụng riêng. Mỗi process có một không gian địa chỉ và một không gian trạng thái riêng. Các process liên lạc với nhau thông qua cơ chế điều phối của HĐH. Hệ điều hành đa nhiệm hiện đại, hỗ trợ thread: Đơn vị cơ bản sử dụng CPU là thread. Thread một đoạn các câu lệnh được thi hành. Mỗi process có một không gian địa chỉ và nhiều thread điều khiển. Mỗi thread có bộ đếm chương trình, trạng thái các thanh ghi và ngăn xếp riêng. Giới thiệu HĐH đa nhiệm Luồng của một quá trình có thể chia sẻ nhau không gian địa chỉ : Biến toàn cục, tập tin, chương trình con, . . . Luồng chia sẻ thời gian sử dụng CPU => Luồng cũng có các trạng thái: Sẵn sàng (ready), Đang chạy (running), Nghẽn(Block) như quá trình. Luồng cung cấp cơ chế tính toán song song trong các ứng dụng. Giới thiệu luồng Main Thread Thread A Thread B Thread C start start start Các thread có thể chuyển đổi dữ liệu với nhau Chương trình Multithread Ứng dụng Multithread 9 Printing Thread Editing Thread Lập trình multithread với Java Cách thực hiện Sử dụng lớp java.lang.Thread public class Thread extends Object { } Sử dụng giao diện java.lang.Runnable public interface Runnable { public void run(); // work thread } +run() «interface» Runnable 1 +currentThread() : Thread +isInterrupted() : bool +sleep(in millis : long) : long +yield() +isAlive() +join() +interrupt() +start() +stop() Thread Trong Java, chúng ta có thể tạo ra các luồng bằng cách sử dụng lớp java.lang.Thread. Ngoài ra chúng ta có thể tạo ra các thread thông qua interface Runnable. Lớp java.lang.Thread Thread trong java là một đối tượng của lớp java.lang.Thread Một chương trình cài đặt thread bằng cách tạo ra các lớp con của lớp Thread. Lớp Thread có 3 phương thức cơ bản: public static synchronized void start() : Chuẩn bị mọi thứ cần thiết để thực hiện thread. public void run(): Chứa mã lệnh thực hiện công việc thực sự của thread. run() được gọi một cách tự động bởi start(). public void stop() : kết thúc một thread. Thread kết thúc khi: Hoặc tất cả các lệnh trong run() đã được thực thi. Hoặc phương thức stop() của luồng được gọi. Lớp java.lang.Thread Tạo và quản lý thread Khi chương trình Java thực thi hàm main() tức là luồng main được thực thi. Luồng này được tạo ra một cách tự động. tại đây: Các luồng con sẽ được tạo ra từ đó Nó là luồng cuối cùng kết thúc việc thực hiện. Trong chốc lát luồng chính ngừng thực thi, chương trình bị chấm dứt Luồng có thể được tạo ra bằng 2 cách: Dẫn xuất từ lớp Thread Dẫn xuất từ Runnable. Tạo thread sử dụng lớp Thread Cài đặt lớp kế thừa từ lớp Thread và override phương thức run() class MyThread extends Thread { public void run() { // thread body of execution } } Tạo thread: MyThread thr1 = new MyThread(); Thi hành thread: thr1.start(); Tạo và thi hành thread: new MyThread().start(); Ví dụ class MyThread extends Thread { // the thread public void run() { System.out.println(" this thread is running ... "); } } // end class MyThread Ví dụ class ThreadEx1 { // a program that utilizes the thread public static void main(String [] args ) { MyThread t = new MyThread(); // due to extending the Thread class (above) // I can call start(), and this will call // run(). start() is a method in class Thread. t.start(); } // end main() } // end class ThreadEx1 Tạo thread sử dụng Runnable class MyThread implements Runnable { ..... public void run() { // thread body of execution } } Tạo thread sử dụng Runnable Tạo đối tượng: MyThread myObject = new MyThread(); Tạo thread từ đối tượng: Thread thr1 = new Thread(myObject); Thi hành thread: thr1.start(); class MyThread implements Runnable { public void run() { System.out.println(" this thread is running ... "); } } // end class MyThread Ví dụ class ThreadEx2 { public static void main(String [] args ) { Thread t = new Thread(new MyThread()); // due to implementing the Runnable interface // I can call start(), and this will call run(). t.start(); } // end main() } // end class ThreadEx2 Ví dụ Threads – Thread States Các trạng thái của thread: New – thread được tạo ra trong bộ nhớ Runnable – thread có thể được thi hành Running – thread đang thi hành Blocked – thread đang bị treo (I/O, etc.) Dead – thread kết thúc Việc chuyển đổi trạng thái thread thực hiện bởi: Thi hành các phương thức trong lớp Thread new(), start(), yield(), sleep(), wait(), notify() Các sự kiện bên ngoài Scheduler, I/O, returning from run() Vòng đời của thread runnable scheduler new dead running blocked new start terminate IO, sleep, wait, join yield, time slice notify, notifyAll, IO complete, sleep expired, join complete Lưu ý Thread chỉ được thi hành sau khi gọi phương thức start() Runnable là interface Có thể hỗ trợ đa kế thừa Thường dùng khi cài đặt giao diện GUI Viết chương trình thi hành song song 3 thread class A extends Thread { public void run() { for(int i=1;i<=5;i++) { System.out.println("\t From ThreadA: i= "+i); } System.out.println("Exit from A"); } } Ví dụ class B extends Thread { public void run() { for(int j=1;j<=5;j++) { System.out.println("\t From ThreadB: j= "+j); } System.out.println("Exit from B"); } } Ví dụ class C extends Thread { public void run() { for(int k=1;k<=5;k++) { System.out.println("\t From ThreadC: k= "+k); } System.out.println("Exit from C"); } } Ví dụ class ThreadTest { public static void main(String args[]) { new A().start(); new B().start(); new C().start(); } } Ví dụ Chạy lần thứ 1 java ThreadTest From ThreadA: i= 1 From ThreadA: i= 2 From ThreadA: i= 3 From ThreadA: i= 4 From ThreadA: i= 5 Exit from A From ThreadC: k= 1 From ThreadC: k= 2 From ThreadC: k= 3 From ThreadC: k= 4 From ThreadC: k= 5 Exit from C From ThreadB: j= 1 From ThreadB: j= 2 From ThreadB: j= 3 From ThreadB: j= 4 From ThreadB: j= 5 Exit from B java ThreadTest From ThreadA: i= 1 From ThreadA: i= 2 From ThreadA: i= 3 From ThreadA: i= 4 From ThreadA: i= 5 From ThreadC: k= 1 From ThreadC: k= 2 From ThreadC: k= 3 From ThreadC: k= 4 From ThreadC: k= 5 Exit from C From ThreadB: j= 1 From ThreadB: j= 2 From ThreadB: j= 3 From ThreadB: j= 4 From ThreadB: j= 5 Exit from B Exit from A Chạy lần thứ 2 Độ ưu tiên Trong Java, mỗi thread được gán 1 giá trị để chỉ mức độ ưu tiên của thread. Khi thread được tạo ra có độ ưu tiên mặc định (NORM_PRIORITY). Sử dụng phương thức setPriority() để thay đổi độ ưu tiên của thread: ThreadName.setPriority(intNumber) MIN_PRIORITY = 1 NORM_PRIORITY=5 MAX_PRIORITY=10 Ví dụ về thread priority class A extends Thread { public void run() { System.out.println("Thread A started"); for(int i=1;i<=4;i++) { System.out.println("\t From ThreadA: i= "+i); } System.out.println("Exit from A"); } } Ví dụ về thread priority class B extends Thread { public void run() { System.out.println("Thread B started"); for(int j=1;j<=4;j++) { System.out.println("\t From ThreadB: j= "+j); } System.out.println("Exit from B"); } } Ví dụ về thread priority class C extends Thread { public void run() { System.out.println("Thread C started"); for(int k=1;k<=4;k++) { System.out.println("\t From ThreadC: k= "+k); } System.out.println("Exit from C"); } } class ThreadPriority { public static void main(String args[]) { A threadA=new A(); B threadB=new B(); C threadC=new C(); threadC.setPriority(Thread.MAX_PRIORITY); threadB.setPriority(threadA.getPriority()+1); threadA.setPriority(Thread.MIN_PRIORITY); System.out.println("Started Thread A"); threadA.start(); System.out.println("Started Thread B"); threadB.start(); System.out.println("Started Thread C"); threadC.start(); System.out.println("End of main thread"); } } Ví dụ về thread priority Threads – Scheduling Bộ lập lịch Xác định thread nào sẽ thi hành Có thể thực hiện dựa trên độ ưu tiên Là một phần của HĐH hoặc Java Virtual Machine (JVM) Thread Scheduling Ví dụ Tạo lớp kế thừa Thread Sử dụng phương thức sleep() Công việc Tạo 4 thread chạy song sọng, mỗi thread sẽ tạm ngưng thi hành một khoảng thời gian ngẫu nhiên. Sau khi kết thúc sleeping sẽ in ra tên thread. 1 // ThreadTester.java 2 // Show multiple threads printing at different intervals. 3 4 public class ThreadTester { 5 public static void main( String args[] ) 6 { 7 PrintThread thread1, thread2, thread3, thread4; 8 9 thread1 = new PrintThread( "thread1" ); 10 thread2 = new PrintThread( "thread2" ); 11 thread3 = new PrintThread( "thread3" ); 12 thread4 = new PrintThread( "thread4" ); 13 14 System.err.println( "\nStarting threads" ); 15 16 thread1.start(); 17 thread2.start(); 18 thread3.start(); 19 thread4.start(); 20 21 System.err.println( "Threads started\n" ); 22 } 23 } 24 25 class PrintThread extends Thread { 26 private int sleepTime; 27 28 // PrintThread constructor assigns name to thread 29 // by calling Thread constructor main kết thúc khi thread cuối cùng kết thúc. 30 public PrintThread( String name ) 31 { 32 super( name ); 33 34 // sleep between 0 and 5 seconds 35 sleepTime = (int) ( Math.random() * 5000 ); 36 37 System.err.println( "Name: " + getName() + 38 "; sleep: " + sleepTime ); 39 } 40 41 // execute the thread 42 public void run() 43 { 44 // put thread to sleep for a random interval 45 try { 46 System.err.println( getName() + " going to sleep" ); 47 Thread.sleep( sleepTime ); 48 } 49 catch ( InterruptedException exception ) { 50 System.err.println( exception.toString() ); 51 } 52 53 // print thread name 54 System.err.println( getName() + " done sleeping" ); 55 } 56 } Gọi constructor lớp cha Sleep có thể ném ra biệt lệ Công việc của thread Đồng bộ hóa Nhiều hơn 1 thread cùng truy cập vào một tài nguyên khó có thể tránh được đụng độ Cần đến đồng bộ hóa. Dùng phương thức đồng bộ hóa: thêm từ khóa synchoronized trước phương thức cần đồng bộ hóa. Dùng câu lệnh đồng bộ hóa Đồng bộ hóa class Parentheses { void display(String s) { System.out.print("(" + s); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Interrupted"); } System.out.println(")"); } } Đồng bộ hóa class MyThread implements Runnable { String str; Parentheses parentTheses; Thread t; public MyThread(Parentheses p, String s) { parentTheses = p; str = s; t = new Thread(this); t.start(); } public void run() { parentTheses.display(str); } } Đồng bộ hóa public class MultiThreadDemo { /** * @param args the command line arguments */ public static void main(String[] args) { Parentheses p = new Parentheses(); MyThread name1 = new MyThread(p, "Bob"); MyThread name2 = new MyThread(p, "Mary"); try { name1.t.join(); // tạm dừng cho đến khi thread kết thúc name2.t.join(); } catch (InterruptedException e) { System.out.println("Interrupted"); } } } Đồng bộ hóa Dùng phương thức đồng bộ synchronized void display(String s) { } Dùng câu lệnh đồng bộ public void run() { synchronized(parentTheses){ p1.display(str); } }
File đính kèm:
- bai_giang_lap_trinh_java_chuong_4_lap_trinh_da_luong_trong_j.pdf