Multithreading: Các cách khởi tạo và sử dụng Java Thread

Java_Multithreading_Live_Scenario.png

Gần đây mình có nhận được một câu hỏi khi đi PV ở một công ty IT, đó là có bao nhiêu cách để khởi chạy 1 Thread trong Java (Create instance & starting). Theo kiến thức sơ khai từ lúc còn đi học của mình là một cách, nhưng thực tế kết quả chính xác lại là hai (yaoming)

Trong bài viết này xin giới thiệu tới các bạn các cách để create và start 1 thread trong Java. Bài viết được tham khảo từ nguồn sau: http://tutorials.jenkov.com/java-concurrency/creating-and-starting-threads.html

1. Creating and Starting Threads

Đơn giản với đoạn code sau là ta đã có thể khởi tạo một thread:

Thread thread = new Thread();

Để khởi chạy Java thread, chúng ta gọi phương thức start():

thread.start();

Ví dụ này không có bất kỳ các tác vụ nào cho các thread thực thi. Do vậy, thread sẽ dừng lại ngay lập tức sau khi nó được bắt đầu.

Để lập trình các tác vụ cho thread, chúng ta có 2 cách sau:

  • Cách thứ nhất là kế thừa class Thread, và override phương thức run().
  • Cách thứ 2 đó là pass một object được implements từ class Runnable (java.lang.Runnable). Hay nói ngắn gọn là: Create thread bằng cách hiện thực từ Interface Runnable

1.1. Thread Subclass (Cách Một)

Cách thứ nhất là kế thừa class Thread, và đưa các tác vụ vào phương thức run() và override phương thức run(). Các tác vụ sẽ được thực hiện khi gọi start(). Dưới đây là một ví dụ của việc tạo ra một phân lớp Java Thread:

public class MyThread extends Thread {
    public void run(){
        System.out.println("MyThread running");
    }
}

Để create và start, ta dùng lệnh:

MyThread myThread = new MyThread();
myTread.start();

Lệnh start() sẽ return ngay sau khi các thread được khởi chạy. Chứ không đợi cho đến khi phương thức run() hoàn thành toàn bộ task. Trong trường hợp này, khi chạy run() nó sẽ in ra "MyThread running".

Bạn cũng có thể tạo ra một lớp con vô danh của Thread như thế này:

Thread thread = new Thread(){
    public void run(){
        System.out.println("Thread Running");
    }
}
thread.start();

Rất đơn giản, ví dụ này sẽ in ra "Thread Running" khi Thread được khởi chạy.

1.2. Runnable Interface Implementation (Cách Hai)

Cách thứ 2 đó là pass một object được implements từ class Runnable (java.lang.Runnable). Hay nói ngắn gọn là: Create thread bằng cách hiện thực từ Interface Runnable. Đơn giản là vì 1 Runnable Object có thể được thực thi bởi 1 Thread. Dưới đây là một ví dụ về Java Runnable:

public class MyRunnable implements Runnable {
    public void run(){
       System.out.println("MyRunnable running");
    }
}

Để thực thi phương thức run() bởi thread, Chúng ta sẽ truyền instance của MyRunnable vào trong constructor của Thread:

Thread thread = new Thread(new MyRunnable());
thread.start();

Khi Thread khởi chạy, sẽ gọi tới phương thức run() của instance MyRunnable thay vì thực thi phương thức run() của nó. Ví dụ trên sẽ in ra "MyRunnable running".

Hoặc ta cũng có thể implement anonymous Runnable như sau:

Runnable myRunnable = new Runnable(){
	public void run(){
		System.out.println("Runnable running");
	}
}

Thread thread = new Thread(myRunnable);
thread.start();

2. Một số thông tin về Thread

  • Mỗi Thread có chứa các thông tin sau:
  • ThreadID: Định danh của Thread, thu được qua phương thức getId() của lớp Thread
  • ThreadName: Tên của Thread, có thể đặt hoặc ko đặt tên (JVM sẽ tự đặt)
  • Priority: Độ ưu tiên của Thread, là thông số quyết định mức ưu tiên khi cấp phát CPU cho Thread. Để set độ ưu tiên ta gọi phương thức setPriority(int newPriority)
  • StackSize: Độ lớn ngăn xếp của Thread (tính bằng byte) mà Thread có thể execute.

3. Thread.currentThread()

Method Thread.currentThread() trả về tham chiều tới Thread instance đang được thực thi. Bằng cách này bạn có thể lấy được quyền truy cập vào các Java Thread object đại diện cho các Thread thực hiện một khối mã lệnh.

Thread thread = Thread.currentThread();

Một khi bạn có một tham chiếu đến Thread object, bạn có thể gọi các method trên nó. Ví dụ, bạn có thể lấy tên của các thread hiện đang thực hiện:

String threadName = Thread.currentThread().getName();

4. Kết luận

Dùng Subclass(Kế thừa lớp Thread) hay Runnable?

Thực tế không có quy ước nào nói rằng phương pháp nào tốt nhất để khởi tạo và chạy Thread. Tuy nhiên việc sử dụng Interface Runnable có một cái lợi là giúp ta kế thừa từ 1 lớp khác ngoài lớp thread, vì nếu sử dụng Subclass thì chỉ có thể thừa kế một lớp Thread vì java không hỗ trợ đa thừa kế.