Một ứng dụng có thể chia làm nhiều nhiệm vụ, mỗi nhiệm vụ có thể gán cho một thread Nhiều thread cùng thực hiện đồng thời, gọi là Multithreading.. Tạo thread Đối tượng thread có t
Trang 1Giới thiệu về Threads
Bài 07
Trang 2 Thiết lập thuộc tính cho threads
Tìm hiểu về daemon thread
Trang 3Multitasking & Multithreading
Multitasking là khả năng chạy 1 or nhiều chương
trình cùng lúc.
Operating system sẽ điều khiển bằng cách lập lịch
cho các chương trình đó.
Multithreading là khả năng thực hiện các phần
khác nhau của một chương trình một cách độc lập
nhau.
Trang 4 Thread là một đoạn mã nhỏ nhất mà có thể thực thi
được, nó thực thi một nhiệm vụ cụ thể nào đó.
Một ứng dụng có thể chia làm nhiều nhiệm vụ, mỗi
nhiệm vụ có thể gán cho một thread
Nhiều thread cùng thực hiện đồng thời, gọi là
Multithreading.
Các thread có vẻ như thực hiện đồng thời, nhưng
thực tế ko phải vậy…
Trang 5Ưu điểm của Multithreading
Multithreading có chi phí thấp hơn multitasking (về
Các tiến trình trong multitasking gọi nhau phải chịu
chi phí lơn hơn các thread trong multithreading.
Multithreading cho phép chúng ta thiết kế chương
trình hiệu quả hơn mà sử dụng ít tài nguyên CPU
Multithreading còn cho phép chúng ta điều khiển cho
các thread sleep một t/g trong khi các thread khác
vẫn hoạt động mà ko làm cho hệ thống bị pause.
Trang 6ứng dụng của thread
Tính toán 2 phép tính đồng thời
Vừa nghe nhạc, vừa xem ảnh đồng thời
Hiển thị cùng lúc nhiều ảnh trên màn hình
Trang 7Tạo threads
Chương trình sẽ bị ngắt quãng khi thread main bị stop
Main thread có thể được điều khiển thông qua đối tượng
thread
Tham chiếu đến main thread có thể nhận được bằng cách gọi
method currentThread() của lớp Thread
Khi chương trình java thực hiện thì luôn có
một thread chạy đó là thread main
Trang 8Tạo thread
Đối tượng thread có thể được tạo theo 2 cách:
Định nghĩa một lớp là lớp con của lớp Thread được định nghĩa trong gói java.lang
class mythread extends Thread
Định nghĩa một lớp là implements của Runnable
interface.
class mythread implements Runnable
Trang 9Tạo thread
Khi phương thức start() được gọi, thì tài nguyên
hệ thống sẽ được cấp phát cho thread đó và nó sẽ
được lập lịch để chạy.
Sau đó phải gọi phương thức run()
Sau khi một thread mới được khởi tạo, chúng
ta có thể gọi phương thức start()để start
một thread, trái lại nó sẽ là một đối tượng
thread rỗng, ko được cấp phát tài nguyên.
Mythread t = new Mythread();
t.start();
Trang 10public void run() {
while(true)
{
try
{ System.out.println("This is the child thread");
Thread.sleep(500);
}
catch(InterruptedException e)
{ } } } }
Tạo thread
Ví dụ
Tạo một thread bằng cách kế thừa lớp Thread.
class MyThread extends Thread
Trang 11Tạo thread
ví dụ 2:
Tạo thread từ việc implement Runnable interface
class MyThread2 implements Runnable
Trang 12Trạng thái của Thread
Born: một thread vừa được tạo ra thì nó ở
trạng thái born
Ready: Sau khi thread được tạo, nó ở trạng thái sẵn sàng đợi phương thức start()
được gọi.
Trang 13Trạng thái của thread
Running: Thread ở trạng thái running khi phương thực start đã được gọi
Sleeping: thread đang hoạt động cũng có thể
bị ngắt quãng bằng cách gọi phương thức
sleep() Thread sẽ chuyển sang trạng thái
sleeping một khoảng thời gian.
Trang 14Trạng thái của thread
Waiting: Thread sẽ ở trạng thái này khi
phương thức wait() được gọi Nó được sử dụng khi 2 hay nhiều thread chạy cùng nhau.
Blocked: thread rơi vào trạng thái này khi
nó đợi dữ liệu như thao tác input/output.
Dead: thread rơi vào trạng thái này khi
phương thức run() kết thúc hoặc phương
Trang 15Các trạng thái của thread
New Thread (BORN)
READY
RUNNING
DEAD SLEEPING
Trang 16Một số method của lớp thread
final boolean isAlive() : trả về giá trị true nếu
thread còn tồn tại
final String getName() : trả về tên của thread.
void start() :
Trang 17Một số method của lớp thread
final void join() throws
InterruptedException : đợi cho đến khi thread
Trang 18Một số method của lớp thread
final boolean isDaemon() : kiểm tra xem có
phải là Daemon thread ko.
static int activeCount(): đếm số thread
đang hoạt động
Trang 19 Thread có thể được xét mức ưu tiên khác nhau (là
2 phương thức để thiết lập priority:
final void setPriority( int newp):
thay đổi mức ưu tiên hiện tại
final int getPriority(): trả về mức ưu tiên.
Trang 20Daemon threads
2 loại thread trong java:
User threads: đc tạo bởi người dùng
Daemon threads: các thread làm việc dưới background và
nó cung cấp dịch vụ cho các thread khác
Ví dụ: – the garbage collector thread
Khi thread của người dùng thoát, JVM sẽ kiểm tra
xem còn các thread nào đang chạy ko?
Nếu có thì nó sẽ lập lịch cho các thread đó
Nếu chỉ có Daemon thread hoạt động thì nó sẽ
thoát.
Trang 21Daemon threads
Chúng ta cũng có thể thiết lập cho một thread là
Daemon thread nếu muốn chương trình chính đợi cho đến khi thread kết thúc.
Thread có 2 phương thức để làm việc với Daemon
thread:
một Thread thành Daemon thread
thread có phải là Daemon thread ko?
Trang 23 Một chương trình có nhiều tuyến cùng chạy đồng thời,
các tuyến dùng chung vùng dữ liệu của chương trình.
Điều phối giữa các tuyến:
Các luồng có quyền ưu tiên cao hơn có cơ hội nhận thời gian
sử dụng CPU để hoàn thành trước các luồng ưu tiên thấp
hơn
Khi một luồng đang được chạy, luồng có quyền ưu tiên cao
hơn có thể giành quyền sử dụng CPU (cơ chế lập lịch của
JVM)
Nếu các luồng có quyền ưu tiên như nhau thì một luồng bất
kì sẽ được lựa chọn
Trang 24 Điều phối giữa các tuyến:
Khi một luồng giành quyền sử dụng CPU thì nó sẽ thực hiện
cho đến khi một trong các sự kiện sau:
Phương thức run() kết thúc.
Một luồng có quyền ưu tiên cao hơn.
Nó gọi sleep() or yield()-nhượng bộ
Khi gọi yield() luồng sẽ đưa cho các luồng khác cùng quyền
ưu tiên cơ hội sử dụng CPU, nếu không có luồng nào khác
cùng quyền ưu tiên tồn tại thì nó sẽ thực hiện tiếp
Khi gọi sleep() luồng sẽ ngủ một khoảng thời gian
mili-seconds, khi đó bất kì một luồng nào khác cũng có thể sử
dụng CPU
Trang 25Một số phương thức của thread
Phương thức join():
Khi một luồng (A) gọi phương thức join() của một luồng nào
đó (B), luồng hiện hành (A) sẽ bị khóa chờ (blocked) cho đến
khi luồng đó kết thúc (B)
Phương thức interrupt():
Đặt trạng thái luồng ngắt (không ngừng hẳn luồng)
Phương thức interrupted()
Phương thức này trả lại một giá trị boolean cho biết trạng
thái ngắt quãng của luồng hiện thời
Phương thức này cũng đặt lại trạng thái của luồng hiện thời
thành không ngắt
Trang 26Đồng bộ luồng
Khi nhiều luồng cùng truy xuất đến một nguồn tài
nguyên -> cần đồng bộ
Ví dụ: đọc/ghi trên cùng 1 file, sửa đổi trên cùng 1 đối tượng
Trong trường hợp này dữ liệu cần phải được đồng bộ,
đảm bảo được trạng thái an toàn.
Để đảm bảo tài nguyên chia sẻ chỉ được truy xuất bởi
một luồng -> ta sử dụng cơ chế synchronization.
Trang 27Đồng bộ luồng
Dùng từ khoá synchronized trên các phương thức để
thực hiện đồng bộ hoá.
Đối tượng khai báo phương thức synchronized sẽ có
một bộ giám sát (monitor) Bộ giám sát đảm bảo tại
mỗi thời điểm chỉ có một tuyến được gọi phương thức
synchronized.
Khi một tuyến gọi phương thức synchronized, đối
tượng sẽ bị khoá Khi tuyến đó thực hiện xong
phương thức, đối tượng sẽ được mở khoá.
Trang 28Đồng bộ luồng
Trong khi thực thi phương thức synchronized, một
tuyến có thể gọi wait() để chuyển sang trạng thái chờ
cho đến khi một điều kiện nào đó xảy ra
Khi thực hiện xong công việc trên đối tượng, một
tuyến cũng có thể thông báo (notify) cho các tuyến
khác đang chờ để truy nhập đối tượng.
Deadlock: Tuyến A chờ tuyến B và tuyến B cũng chờ
tuyến A.
Trang 29Quan hệ Producer-Consumer
Giả sử có 2 tuyến:Producer ghi dữ liệu vào một buffer
và Consumer đọc dữ liệu từ buffer => Cần có sự đồng
bộ hoá nếu không dữ liệu có thể bị Producer ghi đè
trước khi Consumer đọc được hoặc Consumer có thể
đọc một dữ liệu nhiều lần khi Producer chưa sản xuất
kịp.
Trang 30Quan hệ Producer-Consumer
Giải pháp đồng bộ hoá:
Trước khi tiếp tục sinh dữ liệu và đưa vào buffer,
Producer phải chờ (wait) Consumer đọc xong dữ
liệu từ buffer.
Khi Consumer đọc xong dữ liệu, nó sẽ thông báo
(notify) cho Producer biết để tiếp tục sinh dữ liệu.
Nếu Consumer thấy trong buffer không có dữ liệu
hoặc dữ liệu đó đã được đọc rồi, nó sẽ chờ (wait)
cho tới khi nhận được thông báo có dữ liệu mới.
Khi Producer sản xuất xong dữ liệu, nó thông báo
(notify) cho Consumer biết.
Trang 31Vídụvề P-C: Không đồng bộ
class Buffer
{ private int buffer = -1;
public void set( int value )
class Consumer extends Thread
{ private Buffer sharedBuffer;
public Consumer( Buffer shared )
{ super( "Consumer" ); sharedBuffer = shared; }
public void run()
{ for ( int count = 1; count <= 5; count++ )
{ try
{ Thread.sleep( ( int ) ( Math.random() * 3000 ) ); System.out.println( "Consumer reads " +sharedBuffer.get());
} catch ( InterruptedException e ) {e.printStackTrace();}
} System.out.println( getName() + " finished.");
}
public class SharedBufferTest1
{
public static void main( String [] args )
{ // create shared object used by threads
Buffer sharedBuffer = new Buffer();
// create producer and consumer objects
Producer producer = new Producer( sharedBuffer );
Consumer consumer = new Consumer( sharedBuffer );
producer.start(); // start producer thread
consumer.start(); // start consumer thread
}
}
Trang 32Kết quả khi không đồng bộ
Trang 33Vídụvề P-C: đồng bộ
class Buffer // Thiết kế lại lớp Buffer
{
private int buffer = -1;
private boolean writable = true;
public synchronized void set( int value )
Trang 34Kết quả khi đồng bộ
Producer writes 1Consumer reads 1Producer writes 2Consumer reads 2Producer writes 3Consumer reads 3Producer writes 4Consumer reads 4Producer writes 5Producer finished
Consumer reads 5