1. Trang chủ
  2. » Luận Văn - Báo Cáo

Bài giảng lập trình java căn bản chương 9 ths võ đức cẩm hải

50 4 0
Tài liệu đã được kiểm tra trùng lặp

Đ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

Thông tin cơ bản

Tiêu đề Chương 9 - Threads
Trường học Trường Đại học FPT
Chuyên ngành Lập trình java
Thể loại Bài giảng
Năm xuất bản 2023
Thành phố Hà Nội
Định dạng
Số trang 50
Dung lượng 686,69 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Luồng đang thực thi có thể bị tạm ngưng bằng phương thức sleep một thời khoảng và sẽ lại ready sau khi đáo hạn thời gian.. 9.5.2- Tạo luồng với interface Runnable class MyThread implem

Trang 2

Định nghĩa được luồng (thread) là gì Hiểu đa luồng là gì?

Biết cách tạo luồng trong Java.

Hiểu về nhu cầu đồng bộ (synchronize) các luồng.

Biết cách dùng wait() và notify() để giao tiếp giữa các luồng.

Trang 3

9.2- Luồng và đa luồng

9.3- Luồng trong Java

9.4- Trạng thái của luồng

9.5- Lập trình luồng trong Java 9.6- Độ ưu tiên của luồng

9.7- Đồng bộ giữa các luồng 9.8- Deadlock

9.9- Cơ chế Chờ-nhận biết 9.10- Tóm tắt

Trang 4

nhưng các lớp này sử dụng các hỗ trợ phụ

thuộc platform.

LỚp Graphics và Graphics2D trong gói AWT cho

ta các công cụ vẽ hình và xuất file ảnh.

Lớp Applet và JApplet cung cấp khả năng tạo các ứng dụng nhỏ của Java nhúng vào trang Web và chúng được thực thi trong Browser.

appletviewer cho phép chạy một Java applet mà không cần đến Browser.

Trang 5

9.2- Luồng và đa luồng

Luồng- thread: Một dòng các lệnh mà CPU phải thực thi.

Các hệ điều hành mới 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 trong 1 lần làm việc với máy tính  Nhiều ứng dụng được nạp.

Như vậy

chương trình đã được nạp).

– 1 application thông thường khi thực thi là 1 luồng

– Trong 1 application có thể có nhiều luồng Thí dụ chuyển động của 10 đối tượng hiện hành trong 1 trò chơi là 10 luồng.

Trang 6

Kỹ thuật đa luồng

Với máy có m CPU chạy m luồng  Mỗi CPU chạy 1 luồng  Hiệu quả.

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 1 CPU chạy đồng thời k luồng với k>1 Các luồng được quản lý bằng 1 hàng đợi, mỗi luồng được cấp phát thời gian mà CPU thực thi là ti (cơ chế time-slicing –

phân chia tài nguyên thời gian) Luồng ở đỉnh hàng đợi được lấy ra để thực thi trước, sau ti thời gian của mình, luồng này được đưa vào cuối hàng đợi và CPU lấy ra luồng kế tiếp.

Với máy chỉ có 1 CPU mà lại chạy k luồng  Hiệu suất mỗi chương trình sẽ kém

Trang 7

Lợi ích của đa luồng

Tăng hiệu suất sử dụng CPU: Phần lớn thời gian thực

thi của 1 ứng dụng là 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 sự đồng bộ giữa các đối tượng: Thí dụ

như trong 1 trò chơi, các nhân vật cùng nhau chuyển động Trong 1 trang Web, tạo được sự đồng thời của các đường diềm (marquee) như thanh 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) và quyến rũ (captivating).

Quản lý được thời gian trong các ứng dụng như thi online, thời gian chơi một trò chơi.

Trang 8

9.3- Luồng trong Java

Main thread - luồng chính : là luồng chứa các

luồng khác Đây chính là luồng cho Java

Application hiện hành (mức toàn application).

Child thread - luồng con : là luồng được tạo ra

từ luồng khác.

Khi 1 application thực thi, main thread được chạy, khi gặp các phát biểu phát sinh luồng con, các luồng con được khởi tạo Vào thời điểm

luồng chính kết thúc, application kết thúc Java cung cấp lớp Thread

mô tả 1 luồng trong gói java.lang

Trang 9

9.4- Trạng thái của luồng

Sinh ra (Born) new Thread()

stop() hay chạy xong

Hành vi để buộc luồng chuyển trạng thái

run()

Hết thời gian ngủ

notify()

Trang 10

Trạng thái của luồng

Một luồng sau khi sinh ra (born) không được chạy ngay

mà chỉ là sẵn sàng (ready) chạy Chỉ khi nào phương

thức start() được gọi thì luồng mới thực thi (chạy code

phương thức run())

Luồng đang thực thi có thể bị tạm ngưng bằng phương

thức sleep() một thời khoảng và sẽ lại ready sau khi đá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ùng được thực thi, nếu có 1 luồng giữ tài nguyên mà không nhả ra sẽ làm cho các luồng khác không dùng được tài nguyên này (đói tài nguyên) Để

tránh tình huống này, Java cung cấp cơ chế

Wait-Notify(đợi-nhận biết) và cơ chế này được trình bầy ở

mục sau Phương thức wait() giúp đưa 1 luồng vào

trạng thái chờ.

Trang 11

Trạng thái của luồng

Khi một 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()

trong Java 2 dùng cho mục đích này.

Khi 1 suspended thread được mang ra thực thi tiếp, trạng thái của luồng là resumed Phương

thức resume() – version cũ/ notify() trong

Java 2 được dùng cho mục đích này.

Khi 1 luồng chờ biến cố như xuất/nhập dữ liệu

Luồng rơi vào trạng thái blocked.

Khi 1 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).

Trang 12

9.5- Lập trình luồng trong Java

Cách 1: Xây dựng 1 lớp con của lớp java.lang.Thread, override hành vi run() để phù hợp với mục đích bài toán.

Cách 2: Xây dựng 1 lớp có hiện thực interface Runnable

– Không cần import java.lang vì là gói cơ bản.

– java.lang.Thread là lớp Java xây dựng sẵn đã hiện thực interface Runnable.

– Interface java.lang.Runnable chỉ có 1 method run() – Tham khảo thêm trong gói java.lange

Trang 13

Stt.010.Mssv.BKD002ac.email.ninhd 77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77t@edu.gmail.com.vn.bkc19134.hmu.edu.vn.Stt.010.Mssv.BKD002ac.email.ninhddtt@edu.gmail.com.vn.bkc19134.hmu.edu.vnStt.010.Mssv.BKD002ac.email.ninhd 77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77.77.99.44.45.67.22.55.77.C.37.99.44.45.67.22.55.77t@edu.gmail.com.vn.bkc19134.hmu.edu.vn.Stt.010.Mssv.BKD002ac.email.ninhddtt@edu.gmail.com.vn.bkc19134.hmu.edu.vnTham khảo lớp Thread

Trang 14

9.5.1- Tạo luồng là lớp con của lớp Thread

class MyThread extends Thread

{ // dữ liệu + hành vi của lớp

public void run()

{ // hiện thực code phụ thuộc bài toán }

}

Trang 15

9.5.2- Tạo luồng với interface Runnable

class MyThread implements Runnable

{ // dữ liệu + hành vi của lớp

public void run()

{ // hiện thực code phụ thuộc bài toán }

}

Trang 16

9.5.3- Khởi tạo và thực thi 1 luồng

MyThread t = new MyThread(); // tạo 1 luồng t.start(); // chỉ thị cho luồng thực thi

Hành vi start() sẽ tự động gọi hành vi run()

Trang 17

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 của luồng được tạo ra

Trang 18

9.5.5- Hai loại luồng

Luồng Daemon: luồng hệ thống, chạy ở

mức nền (background- chạy ngầm), là những luồng cung cấp các dịch vụ cho các luồng khác Các quá trình trong JVM chỉ tồn tại khi các luồng daemon tồn tại JVM

có ít nhất 1 luồng daemon là luồng

“garbage collection”

Luồng do user tạo ra.

Trang 19

9.5.6- Methods thông dụng của lớp Thread

final void setName( String

NewName)

Đặt tên mới cho luồng

final void join () throws interruptedException

void setDaemon(boolean on) on=true : luồng là daemon

on=false : luồng của user

Trang 20

9.5.6- Methods thông dụng của lớp Thread

static void sleep (long milisec)

Trì hoãn luồng 1 thời gian

static int activeCount() Đếm số luồng đang tích cực

static void yield() Tạm dừng luồng hiện hành để các

luồng khác tiếp tục thực thi

Trang 21

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 con của luồng cha hiện 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 con }

}

Kết qủa:

This is main thread This is child thread Pres any key to continue

Trang 22

Minh họa tạo luồng với lớp interface Runnable

class Thread2 implements Runnable

{ public void Create()

{ Thread t = new Thread(this);

t.start();

}

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

}

This is child thread Pres any key to continue

Khi xây dựng luồng bằng interface Runable, phải khai báo 1 đối tượng Thread và gọi hành vi start() để hành vi này gọi

run()

Trang 23

MInh họa một số methods của Thread

class Thread3 implements Runnable // Thread3.java

public void run()

{ int n= Thread.activeCount(); // Đếm số luồng đang tích cực trong JVM

System.out.println("Number of active threads:" + n);

String t1Name = t1.getName(); // lấy tên của 2 luồng

String t2Name = t2.getName();

System.out.println("Name of t1 thread:" + t1Name);

System.out.println("Name of t2 thread:" + t2Name);

System.out.println("Is t1 thread a daemon? :" + t1.isDaemon());

System.out.println("Is t2 thread a daemon? :" + t2.isDaemon());

System.out.println("Is t1 thread alive? :" + t1.isAlive());

System.out.println("Is t2 thread alive? :" + t2.isAlive());

}

public static void main (String args[])

{ System.out.println("This is main thread.");

Thread3 t= new Thread3();

} }

Kết quả This is main thread.

Number of active threads:4 Name of t1 thread:Thread-1 Name of t2 thread:Thread-2

Is t1 thread a daemon? :false

Is t2 thread a daemon? :true

Is t1 thread alive? :true

Is t2 thread alive? :false Press any key to continue

Tên mặc định của luồng là Thread-n, với n là số thứ tự khi luồng được tạo ra

Kết qủa là 4 luồng tích cực : luồng gom rác, luồng mẹ và 2 luồng t1,t2.

Trang 24

Minh họa về trạng thaí của 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 5 secs.");

} catch( InterruptedException e) { System.out.println("thread is interrupted!");

} }

public static void main (String args[])

{ new Thread4();

} }

t thread is born and ready.

Trang 25

9.6- Độ ưu tiên của luồng

Các luồng cùng chia sẻ thời gian của CPU  Luồng ở cuối hàng đợi sẽ lâu được CPU thực thi  Có nhu cầu thay đổi độ ưu tiên của luồng Java cung cấp 3 hằng mô

tả độ ưu tiên của 1 luồng (các độ ưu tiên khác dùng 1 số nguyên từ 1 10).

NORM_PRIORITY : mang trị 5 MAX_PRIORITY : mang trị 10

MIN_PRIORITY : mang trị 1

Độ ưu tiên mặc định của 1 luồng là NORMAL_PRIORITY Luồng con có cùng độ ưu tiên với luồng cha (do đặc điểm thừa kế)

Trang 26

Thao tác với độ ưu tiên của luồng

final void setPriority( int newPriority) final int getPriority()

Như vậy, các điều kiện để 1 luồng không được thực thi:

Luồng không có được độ ưu tiên cao nhất để dành lấy thời gian của CPU.

Luồng bị cưỡng bức ngủ bằng hành vi sleep() Luồng bị chờ do hành vi wait().

Luồng bị tường minh nhận hành vi yield().

Luồng bị khóa vì đang chờ I/O

Trang 27

Minh họa về độ ưu tiên của luồng

class Thread5 extends Thread// Thread4.java

{

public void run()

{ Thread Child = new Thread(this);

System.out.println("Priority of child:" + Child.getPriority());

}

public static void main (String args[])

{ Thread5 t = new Thread5();

t.start();

t.setName("Parent thread");

} }

Name of current thread:Parent thread Piority of current thread:5

Name of child:Child thread Priority of child:5

Press any key to continue

Nếu trong main(), thêm dòng t.setPriority (8); trước dòng t.start();

ta có kết qủa là 8 thay vì 5

Trang 28

9.7- Đồng bộ các luồng

Tình huống: Có hai luồng t1, t2 cùng truy xuất 1

đối tượng dữ liệu là biến m t1 muốn đọc biến m còn t2 muốn ghi biến m  dữ liệu mà t1 đọc được có thể không nhất quán.

 Nếu để cho t2 ghi m trước rồi t1 đọc sau thì t1 đọc được dữ liệu nhất quán tại thời điểm đó.

 Cần có cơ chế để chỉ cho phép 1 luồng được truy xuất dữ liệu chung (shared data) tại 1 thời điểm.

 Kỹ thuật này gọi là “ĐỒNG BỘ HÓA –

SYNCHRONIZATION”

Trang 29

Kỹ thuật cơ bản về đồng bộ hóa

của các luồng mỗi lần chỉ cho 1 luồng bằng từ khóa

synchronized

Mọi đối tượng luồng đều được đối tượng quản lý này quan sát (MONITOR) bằng cách cho mọi đối tượng luồng có dữ liệu là đối tượng monitor này và thay vì

hoặc là 1 biến boolean để nhận biết đã có 1 luồng đang thực thi.

 Luồng đang được chiếu cố gọi là luồng đang có

monitor

Trang 30

Minh họa về đồng bộ các luồng bằng MONITOR

// Monitor1.java – Lớp làm nhiệm vụ xuất hộ 1 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!");

} } }

Chương trình sau sẽ xuất 3 số 10,11, 12 ra màn hình, mỗi số được 1 luồng thực thi.

Từ khóa synchronized khai báo có quản lý việc đồng bộ các luồng

Trang 31

Minh họa về đồng bộ các luồng bằng MONITOR

class OutNum implements Runnable // luồng { Monitor1 monitor; // Luồng có dữ liệu là monitor

int number; // dữ 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;

Trang 32

class Synchro // lớp của chương trình chính

{ public static void main (String args[])

{ Monitor1 monitor = new Monitor1();

int num = 10;

OutNum Obj1 = new OutNum(monitor,num++);

OutNum Obj2 = new OutNum(monitor,num++);

OutNum Obj3 = new OutNum(monitor,num++);

// wait for 3 threads to end

try { Obj1.t.join();

Obj2.t.join();

Obj3.t.join();

} catch(InterruptedException e) { System.out.println ("Thread was interrupted!"); } }

}

Minh họa về đồng bộ các luồng bằng MONITOR

3 luồng có 3 trị khác nhau là 10,11, 12 nhưng

có chung 1 monitor

Trang 33

Kỹ thuật đồng bộ luồng theo khối

Đồng bộ một khối tác vụ.

Người lập trình có thể không muốn dùng các synchronized method để đồng bộ truy xuất đến đối tượng.

Các lớp được cung cấp bởi các thư viện hay do “một ai đó” cung cấp – lớp đã xây dựng- nên không thể thêm từ khóa

synchonized vào được các method

này.

Trang 34

Kỹ thuật đồng bộ luồng theo khối

Cú pháp đồng bộ khối

synchronized (Object) { <các lời gọi methods của Object cần phải được đồng bộ>

}

Buộc phải có { } dù chỉ có 1 phát biểu

Trang 35

Minh họa đồng bộ khối

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

} } }

Chương trình sau viết lại chương trình trước, bỏ qua từ khóa synchronized trong lớp Monitor1 ( ở đây gọi là lớp Monitor2)

Trang 36

Minh họa đồng bộ 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 3 threads to end

try { Obj1.t.join();

Obj2.t.join();

Obj3.t.join();

} catch(InterruptedException e) { System.out.println ("Thread was interrupted!"); }

} }

Ngày đăng: 21/08/2023, 03:30

🧩 Sản phẩm bạn có thể quan tâm