Khái niệm Thread trong java

595

Khái niệm Thread

Có một định nghĩa về Thread như sau :

Thread là một dòng các điều khiển trong một process hay một ứng dụng. Nguyên văn là : Threads are multiple flows of control within a single program or process.

Với cơ chế Multithreading ứng dụng của bạn có thể thực thi đồng thời nhiều dòng lệnh cùng lúc. Có nghĩa là bạn có thể làm nhiều công việc đồng thời trong cùng một ứng dụng của bạn. Có thể hiểu một cách hết sức đơn giản: hệ điều hành với cơ chế đa nhiệm cho phép nhiều ứng dụng chạy cùng lúc. Thì với cơ chế đa luồng, mỗi ứng dụng của bạn có thể thực hiện được nhiều công việc đồng thời.

Bạn sẽ hỏi tại sao không dùng nhiều processes , sao không là Multiprocessing mà lại cần đến Multithreading?

Câu trả lời đơn giản nhất là: Việc tạo ra và quản lý các process đòi hỏi nhiều tài nguyên của hệ thống (cả RAM và CPU) nhiều hơn rất nhiều so với việc tạo ra một Thread. Trong khi đó bạn có thể chỉ cần tạo ra một thread để thực hiện song song một công việc hết sức đơn giản cùng với một công việc chính.

Bạn viết một ứng dụng Java trên bất kỳ nền tảng nào. Khi ứng dụng bạn chạy thì thực sự đã có một bản sao của JVM khởi động và ứng dụng của bạn là một Thread nếu bạn không dùng Multithreading hoặc là nhiều Threads nếu bạn dùng Multithreading.

Tạo một Thread

Như đã nói, mỗi khi chạy một ứng dụng trong Java thì bạn đã có một Thread. Đây là Thread chính, nó thực thi các dòng lệnh trong phương thức: public static void main . Đây là một điểm nhập bắt buộc cho mọi ứng dụng độc lập.

Để tạo ra một Thread khác ngoài Thread chính trên, Java cung cấp cho chúng ta hai cách :

– Tạo ra một lớp con của lớp Thread (java.lang.Thread)

– Tạo ra một lớp hiện thực interface Runnable

Chúng ta sẽ tìm hiểu lần lược hai cách trên.

Tạo một lớp con của lớp java.lang.Thread

Bạn khai báo như sau :

class A extends Thread {  

         public void run() {  

                 ... // code for the new thread to execute  

         }  

 }  

 ...  

 A a = new A(); // create the thread object  

 a.start(); // start the new thread executing  

 ...

Với cách này các dòng lệnh của bạn sẽ được đặt trong method run(). Method này được override method nguyên thuỷ của lớp Thread.

Sau đó bạn sẽ tạo ra một đối tượng từ lớp của bạn.

Bạn gọi phương thức start() từ đối tượng đó. Lúc này Thread của bạn chính thức được tạo ra và phương thức start sẽ tự gọi method run của bạn và thực thi các dòng lệnh mà bạn đã đặc tả.

Chú ý rằng : method start() là method của hệ thống, nó có nhiệu vụ cấp phát bộ nhớ, tạo ra một Thread và gọi hàm run() của bạn. Vì thế bạn không nên override phương thức này. Điều này có thể dẫn đến không tạo được Thread.

Hiện thực interface Runnable

Bạn khai báo như sau :

class B extends … implements Runnable {  

         public void run() {  

                 ... // code for the new thread to execute  

         }  

 }  

 ...  

 B b = new B(); // create the Runnable object  

 Thread t = new Thread(b); // create a thread object  

 t.start(); // start the new thread  

 ...

Cũng giống như cách trên, dòng lệnh của bạn đặt trong method run() (có thể gọi đến các phương thức khác, nhưng phải bắt đầu trong phương thức này)

Sau đó bạn tạo một đối tượng B từ lớp đã hiện thực interface Runnable, tạo thêm một đối tượng t của lớp Thread với thông số cho constructor là đối tượng B.

Sau đó khi bạn gọi phương thức t.start() thì chính thức Thread được tạo ra và phương thức run() của bạn sẽ được triệu gọi một cách tự động.

Bạn sẽ hỏi tại cách thứ hai vẫn phải tạo ra một đối tượng Thread. Vậy tại sao lại đưa ra hai cách hiện thực làm gì ?
Câu trả lời là :

– Bản thân ngôn ngữ Java không hỗ trợ đa thừa kế . Bạn chỉ có thể extends từ một lớp duy nhất. Nhưng bạn lại có thể implements cùng lúc nhiều interface. Khi mà lớp của bạn đã [extends] một lớp nào đó rồi (vd : Applet), thì bạn chỉ có thể implements Runnable để tạo ra Thread.

– Việc extends lớp Thread có thể dẫn đến rủi ro là bạn override các method start(), stop(), … thì có thể làm cho việc tạo Thread là không thể.

Một lời khuyên là nên tạo ra một lớp hiện thực interface Runnable (cách thứ hai) khi muốn tạo ra một Thread. Chương trình của bạn sẽ trong sáng và dễ tìm lỗi hơn.

Các constructor cho lớp Thread

public Thread()

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(null, null, gname) với gname là một tên được phát sinh tự động bởi JVM (máy ảo java) ở dạng Thread-n , với n là một số nguyên.

public Thread(Runnable target)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(null, target, gname) với gname là tên được phát sinh tự động bởi JVM (máy ảo java) ở dạng Thread-n , với n là một số nguyên.

public Thread(ThreadGroup group, Runnable target)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(group, target, gname) với gname là tên được phát sinh tự động bởi JVM (máy ảo java) ở dạng Thread-n , với n là một số nguyên.

– Constructor này có thể phát sinh một ngoại lệ SecurityException nếu như Thread hiện tại không có quyền tạo một Thread mới trong nhóm group.

public Thread(String name)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(null, null, name).

public Thread(ThreadGroup group, String name)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(group, null, name).

– Constructor này có thể phát sinh một ngoại lệ SecurityException nếu như Thread hiện tại không có quyền tạo một Thread mới trong nhóm group.

public Thread(Runnable target, String name)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(null, target, name).

public Thread(ThreadGroup group, Runnable target, String name)

– Tạo ra một đối tượng lớp Thread.

– group là nhóm các Thread mà Thread được tạo mới này sẽ được thêm vào.
– target là đối tượng cần chạy. Tức là trong đối tượng này có method run, chứa các dòng lệnh cần thực thi của chúng ta.
– name là tên của thread.

– Nếu group là null và có một bộ quản lý bảo mật security manager (ta thiết lập cho JVM, mặc định thì không có) thì gruop được xác định bởi method getThreadGroup của security manager. Nếu group null và không có security manager hay phương thức getThreadGroup trả về null thì group là nhóm mà Thread đang hoạt động thuộc về.

– Nếu target là null thì sau khi được khởi hoạt, method run của lớp Thread sẽ được gọi. Nếu target không null thì sau khi được khởi hoạt thì method run của target sẽ được gọi.

– Độ ưu tiên (priority) của Thread mới sẽ được thiết lập bằng với độ ưu tiên của Thread tạo ra nó.

– Constructor này có thể phát sinh một ngoại lệ SecurityException nếu như Thread hiện tại không có quyền tạo một Thread mới trong nhóm group.

Một số phương thức chính của lớp Thread

public static Thread currentThread()

– Phương thức này là một phương thức tĩnh. Có nghĩa là bạn có thể gọi nó ở bất đâu mà không cần phải tạo một đối tượng của lớp Thread.

– Cú pháp để gọi phương thức này là : Thread.currentThread()

– Phương thức này trả về một đối tượng của lớp Thread. Đối tượng này thể hiện cho Thread mà đang thực thi dòng lệnh này.

public long getId()

– Phương thức này trả về một số nguyên là định danh của Thread.

– Con số này là do máy ảo Java (JVM) tạo ra.

public final String getName()

– Phương thức này trả về tên của Thread.

public final void setName(String name)

– Thay đổi tên của thread bằng tên name.

public Thread.State getState()

– Trả về trạng thái hiện tại của thread.

– Là một hằng của lớp Thread.

– Các giá trị có thể là :

+ NEW : thread chưa được khởi hoạt.
+ RUNNABLE : thread đang hoạt động trong JVM.
+ BLOCKED : thread chờ một monitor để unlock một đối tượng mà nó cần.
+ WAITING : thread chờ không giới hạn cho đến khi một thread khác đánh thức nó.
+ TIMED_WAITING : thread chờ trong một thời gian nhất định, hoặc là có một thread khác đánh thức nó.
+ TERMINATED : thread đã kết thúc công việc của nó.

public static void yield()

– Đây là một phương thức tĩnh.

– Phương thức này sẽ làm cho Thread hiện thời tạm ngưng hoạt động để nhường cho một Thread khác hoạt động.

public static void sleep(long millis) throws InterruptedException

public static void sleep(long millis, int nanos) throws InterruptedException

– Đây là một phương thức tĩnh.

– Phương thức này làm cho Thread hiện tại ngừng hoạt động trong một thời gian millis milliseconds.

– Phương thức này có thể phát sinh một ngoại lệ InterruptedException nếu có một Thread nào đó làm ngưng hoạt động Thread này. (Nhưng không hợp lệ, tức là không dùng các phương thức được cho phép).

public void start()

– Phương thức này chính thức tạo ra một đối tượng Thread. Và JVM sẽ tự động gọi phương thức run của đối tượng này nếu nhưng target là null. Hoặc sẽ gọi phương thức run của target nếu như target khác null.

– Tuyến được bắt đầu hoạt động sau khi phương thức này được gọi thành công.

– Phương thức này có thể phát sinh một ngoại lệ IllegalThreadStateException nếu Thread này đã được khởi hoạt.

public final boolean isAlive()

– Phương thức này kiểm tra xem Thread có còn hiệu lực hay không (còn sống).

– Một Thread còn sống khi mà nó đã

(Nguồn SinhvienIT)