Cụ thể các phương thức trên đây là như thế nào thì mời các bạn đến bài học sau sẽ rõ. Bài hôm nay chúng ta thử thực hành với phương thức join(). Khi một Thread gọi đến phương thức join() của Thread khác, nó sẽ phải đợi Thread khác đó chết đi thì nó mới được thực hiện tiếp tác vụ còn lại của nó.

Lưu ý rằng các phương thức mình liệt kê trên đây không có tham số truyền vào nhé.

Chúng ta cùng đến với bài thực hành để hiểu rõ hơn về trạng thái này của Thread.

Bài Thực Hành Số 4

Trước hết chúng ta cùng chỉnh sửa một tí lớp MyRunnable như sau.

public class MyRunnable implements Runnable {

	@Override
	public void run() {
		System.out.println("MyRunnable Start");
		for (int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("MyRunnable End");
	}

}

Code trên đây chưa liên quan gì đến việc đưa Thread vào trạng thái WAITING đâu nhé. Code này chỉ có in ra console cho thấy MyRunnable vừa được “Start”, rồi cho làm một việc nặng nặng nào đó, như lặp 100 lần, mỗi lần lặp sẽ ngủ 100 mili giây thôi. Cuối cùng sẽ in ra console cho thấy MyRunnable đã “End”.

Tiếp theo chúng ta đến với lớp MyThread. Ở MyThread này, khi được khởi chạy, chúng ta cố tình khai báo rồi khởi chạy MyRunnable luôn. Nhưng khi vừa mới khởi chạy MyRunnable, chúng ta gọi đến phương thức join() của nó. Điều này báo với hệ thống rằng, MyThread này sẽ đợi MyRunnable chạy hết (kết thúc vòng đời của MyRunnable) thì MyThread mới chạy tiếp. Bạn cứ code rồi khởi chạy nhé, đền bài học sau mình sẽ nói rõ hơn về phương thức join() này.

Đây là code của MyThread.

public class MyThread extends Thread {

	@Override
	public void run() {
		System.out.println("MyThread Start");
		Thread myRunnableThread = new Thread(new MyRunnable());
		myRunnableThread.start();
		
		try {
			myRunnableThread.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println("MyThread End");
	}
}

Sau đó ở phương thức main() bạn chỉ cần khởi chạy MyThread, đợi khoảng 100 mili giây thì in trạng thái của MyThread ra console để xem chơi. Sở dĩ phải đợi một tí mới in trạng thái của MyThread là vì để đảm bảo MyThread có đủ thời gian để khởi chạy MyRunnable nữa, rồi thời gian mà MyThread vào WAITING nhường cho MyRunnable nữa, bạn in vội quá thì khó mà trông thấy trạng thái của MyThread.

public static void main(String[] args) {
	MyThread myThread = new MyThread();
		
	myThread.start();
		
	try {
		Thread.sleep(100);
		System.out.println("MyThread State: " + myThread.getState());
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
		
}

Kết quả in ra console như sau.

Kết quả bài thực hành số 4 - Vòng đời của thread

TIMED_WAITING

Cũng tương tự với WAITING trên kia thôi, nhưng khi này các phương thức khiến một Thread “nhường” cho một Thread khác thực thi có truyền vào đối số là khoảng thời gian mà Thread đó nhường. Các phương thức đó là.

Thread.sleep(long milis)
Object.wait(int timeout) hay Object.wait(int timeout, int nanos)
Thread.join(long milis)
LockSupport.parkNanos()
LockSupport.parkUtil()

Chà, phương thức sleep() quen thuộc lắm đúng không. Giờ thì bạn mới hiểu, rằng ở đâu đó trong Thread khi gọi đến Thread.sleep() này, thì Thread đó sẽ rơi vào trạng thái TIMED_WAITING“nhường” cho các Thread khác chạy trong khoảng thời gian mili giây chỉ định trước.

Tuy nhiên chúng ta cũng sẽ nói rõ các phương thức này ở bài học sau. Giờ thì xem code của các bài thực hành nào.

Bài Thực Hành Số 5

Với bài thực hành này bạn chỉ cần chỉnh sửa một chút so với Bài thực hành 4 trên kia. Cái nơi mà MyThread khởi chạy MyRunnable rồi gọi join() để nhường cho MyRunnable í, giờ bạn hãy truyền giá trị mili giây vào phương thức join() này. Nó có nghĩa rằng là tuy MyThread có nhường MyRunnable chạy trước đấy, nhưng chỉ nhường với một khoản thời gian đã chỉ định thôi, hết thời gian đó là tao chạy, đụng ai thì đụng nhé.

public class MyThread extends Thread {

	@Override
	public void run() {
		System.out.println("MyThread Start");
		Thread myRunnableThread = new Thread(new MyRunnable());
		myRunnableThread.start();
		
		try {
			myRunnableThread.join(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println("MyThread End");
	}
}

Nếu bạn thực thi chương trình, hãy để ý kỹ, sau khi in ra “MyThread State: TIMED_WAITING” rồi, MyThead sẽ đợi MyRunnable trong khoảng thời gian (chưa tới) 500 mili giây còn lại, và sẽ in ra “MyThread End”. Vấn đề là MyRunnable vẫn chưa kết thúc vòng lặp, nên mãi sau nó mới kết thúc và in ra “MyRunnable End”. Bạn có thấy sự nhịp nhàng giữa các Thread không nào.

Kết quả bài thực hành số 5 - Vòng đời của thread

TERMINATED

Trạng thái này đánh dấu sự kết thúc vòng đời của Thread. Xảy ra khi Thread kết thúc hết các tác vụ bên trong phương thức run() của nó, hoặc có những kết thúc một cách không bình thường khác, như rơi vào Exception chẳng hạn.

Bài Thực Hành Số 6

Code của bài này không có gì nhiều. Bạn cứ lấy code của Bài thực hành số 5 trên kia. Rồi ở phương thức main(), bạn sleep() lâu lâu một tí, nhằm mục đích đợi cho MyThread kết thúc tác vụ của nó rồi thì in trạng thái của nó ra. Mình cho thời gian ngủ là 20 giây, như sau.

public static void main(String[] args) {
	MyThread myThread = new MyThread();
		
	myThread.start();
		
	try {
		Thread.sleep(20000);
		System.out.println("MyThread State: " + myThread.getState());
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
		
}

Kết quả in ra console như sau.

Kết quả bài thực hành số 6 - Vòng đời của thread

Phù! Chúng ta vừa đi qua kiến thức về vòng đời của một Thread, qua đó chúng ta biết được một Thread sẽ trải qua các trạng thái của nó như thế nào trong suốt đời sống của nó. Chắc bạn cũng biết rằng không phải lúc nào một Thread cũng trải qua cả đủ các trạng thái kể trên đâu nhé, có Thread chỉ NEW, RUNNABLE rồi TERMINATED thôi. Tuy nhiên qua kiến thức về vòng đời này, bạn cũng đã biết được sơ sơ cách các Thread đồng bộ hoá, nhường nhịn nhau để thực thi các tác vụ như thế nào rồi đúng không nào. Và kiến thức về Thread cũng còn khá nhiều và không kém phần thú vị. Hẹn các bạn ở các bài học sau.

Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy ủng hộ blog bằng cách:

Đánh giá 5 sao bên dưới mỗi bài nếu thấy thích.
Comment bên dưới mỗi bài nếu có thắc mắc.
Để lại địa chỉ email của bạn ở thanh bên phải để nhận được thông báo sớm nhất khi có bài viết mới.
Chia sẻ các bài viết của Yellow Code Books đến nhiều người khác.

 

Bài Kế Tiếp

Bài kế tiếp chúng ta sẽ nói cụ thể hơn về các phương thức bên trong một Thread mà bài hôm nay bạn đã có dịp làm quen một ít rồi đấy. Để xem các phương thức này giúp ích gì cho việc quản lý các Thread có trong hệ thống nhé.