Bài 2: Tạo Thread Và Vòng Đời Thread

Định nghĩa và start một thread:

Một ứng dụng tạo một instance của Thread phải cung cấp code sẽ chạy trong thread đó. Có 2 cách để làm điều này:

  • Cung cấp một đối tượng Runnable: Giao diện Runnable định nghĩa một phương thức đơn, phương thức run(). Khi bạn implement giao diện Runnable, bạn phải cài đặt code trong phương thức run(). Đối tượng Runnable được gán cho Contructor của Thread, ví dụ HelloRunnable:

public class HelloRunnable implements Runnable {

public void run() {
System.out.println(“Hello from a thread!”);
}

public static void main(String args[]) {

(new Thread(new HelloRunnable())).start();
}
}

  • Tạo một class extend từ Thread: Bản thân lớp thread đã implement giao diện Runnable, phương thức run() của nó không làm gì cả. Một ứng dụng tạo ra 1 lớp extend từ thread, phải cung cấp phần thực thi của phương thức run(), ví dụ:

public class HelloThread extends Thread {

public void run() {

System.out.println(“Hello from a thread!”);

}

public static void main(String args[]) {

(new HelloThread()).start();

}

}

Chú ý cả 2 ví dụ đều gọi Thread.start() để bắt đầu thread mới.

Vậy bạn nên sử dụng 2 trường hợp trên trong điều kiện nào. Ở trường hợp đầu tiên, sử dụng đối tượng Runnable, lớp implement giao diện này có thể kế thừa từ một lớp khác. Ở trường hợp thứ hai, lớp extend từ thread thì không thể kế thừa thêm lớp nào ngoài thread, bởi Java chỉ cho phép đơn thừa kế.

Lớp thread định nghĩa một số phương thức hữu ích cho việc quản lý Thread. Chúng bao gồm các phương thức tĩnh cung cấp thông tin hay tác động đến trạng thái của thread gọi các phương thức này. Các phương thức khác được gọi từ các thread khác liên quan đến việc quản lý thread và đối tượng Thread.

Trạng thái của Thread

Một Thread bao gồm 4 trạng thái sau:

  • New
  • Runnable
  • Blocked
  • Dead

Trạng thái New:

Khi tạo một Thread với toán tử new, thì Thread vẫn chưa được chạy. Điều này có nghĩa là nó ở trong trạng thái New. Khi một Thread ở trong trạng thái New, Thread vẫn chưa bắt đầu thực thi code ở bên trong nó.

Trạng thái Runnable:

Khi gọi phương thức start(), thì Thread rơi vào trạng thái Runnable. Khi ở trong trạng thái này, một Thread hoặc có thể đang chạy hoặc không, nhưng không có điều gì có thể ngăn cản nó thực thi nếu sheduler có thể sắp xếp nó. Nó phụ thuộc vào hệ điều hành gán thời gian thực thi cho nó. Và nó không phải là dead hay blocked.

Trạng thái Blocked:

Thread rơi vào trạng thái Blocked nếu một trong các action sau đây xảy ra:

  • Gọi phương thức sleep().
  • Thread gọi một operation mà nó đang bị blocking trên Input/Output.
  • Thread cố gắng giành lấy khóa(lock) trong khi khóa này đang được nắm giữ bởi một Thread khác.
  • Thread đang đợi một điều kiện nào đó để thực thi.
  • Một ai đó gọi phương thức suppend() của Thread. Tuy nhiên, phương thức này đã bị phản đối và không nên gọi nó trong code. Tóm lại, khi một Thread ở trong trạng thái blocked, scheduler sẽ bỏ qua nó và không cho nó thời gian CPU để xử lý, và nó không thể thực thi bất kỳ hoạt động nào.

Trạng thái Dead:

Một Thread rơi vào trạng thái Dead với một trong 2 lý do sau:

  • Thực thi xong phương thức run().
  • Một ngoại lệ chưa được bắt(uncaught) được phát sinh và kết thúc phương thức run().

Ngoài ra, có một cách khác có thể kill một Thread bằng cách gọi phương thức stop(). Tuy nhiên, phương thức này đã bị ngăn cấm và không nên sử dụng phương thức này trong code.

Quyền ưu tiên(Priority)

  • Mỗi Thread trong Java đều có một quyền ưu tiên(priority) giúp cho hệ điều hành xác định được thứ tự thực hiện của các Thread được thực thi.
  • Giới hạn của nó:  MIN_PRIORITY(có giá trị 1) và MAX_PRIORITY(có giá trị 10).
  • Thông thường, Thread có quyền ưu tiên cao hơn sẽ được ưu tiên xử lý. Theo mặc định,  mỗi một Thread được cho một quyền ưu tiên NORM_PRIORITY(có giá trị 5).
  • Hầu hết Java Platforms đều hỗ trợ bảng biểu làm việc(timeslicing). Nếu không có timeslicing, thì mỗi Thread trong tập hợp các Thread có quyền ưu tiên ngang nhau đều thực thi (trừ khi nó từ trạng thái runnable rơi vào trạng thái waiting hay timed waiting, hay bị ngắt bởi Thread có quyền thực thi cao hơn) trước khi các Thread khác có quyền ưu tiên ngang nhau nhận được cơ hội thực thi. Với Timeslicing, thậm chí nếu Thread chưa thực thi xong khi thời gian thực thi vượt quá giới hạn cho phép, thì processor sẽ đẩy Thread đó ra và đưa một Thread tiếp theo(có độ ưu tiên bằng Thread trước đó) vào để thực thi.
  • Lưu ý:Những constants(MAX_PRIORITY, MIN_PRIORITY) được khai báo trong lớp Thread. Và ta không tạo và sử dụng các đối tượng Thread để thực thi đồng thời mà phải thực thi giao diện Runnable.

Các bài liên quan:
Tìm hiểu Thread trong JAVA-Phần 1