Mở đầu
Bạn đã từng nghe nhiều về Multithreading. Ban đã biết về bộ xử lý Dual core của intel của AMD. Bạn biết rằng các công nghệ đó hỗ trợ việc xử lý song song...
Bạn có biết rằng bản thân ngôn ngữ Java cũng hỗ trợ Multithreading. Với bài viết này, tôi hi vọng sẽ giúp các bạn tìm hiểu sơ lược về Thread trong Java. Một lĩnh vực khá thú vị.
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 method : 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 :
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 đã đặt 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 ko tạo được thread.
Hiện thực interface Runnable
Bạn khai báo như sau:
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à: bạn 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
- 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.
- 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.
- 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.
- 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).
- 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.
- 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).
- 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.
Chi tiết hơn bạn có thể xem ở Java API của bộ JDK
Một số phương thức chính của lớp Thread
- 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.
- 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.
- Phương thức này trả về tên của thread.
- Thay đổi tên của thread bằng tên name.
- 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ó.
- Đâ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.
- Đâ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).
- 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.
- 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ó đã được khởi hoạt và chưa kết thúc công việc của nó.
- Trả về nhóm Thread mà thread này thuộc về
- Đây là phương thức được gọi bởi một thread khác.
- Phương thức này làm cho thread gọi phải ngưng hoạt động và chờ trong một khoảng thời gian millis millisecond hoặc chờ trong khoảng thời gian millis millisecond và nanos nanosseconds, hoặc chờ cho đến khi thread này kết thúc thì mới tiếp tục hoạt động.
- Phương thức này có thể phát sinh một ngoại lệ InterruptedException nếu nó bị một thread khác làm ngưng hoạt động.
- Trả về một thể hiện dạng String của thread này.
- Thể hiện này bao gồm tên, độ ưu tiên và nhóm.
- Các methods này đều được khuyến cáo là không nên dùng. Sẽ bị bỏ trong các phiên bản sau của bộ JRE và JDK.
- Bởi vì các methods này làm cho các monitor của hệ thống (được JVM tạo ra để giám sát các đối tượng của người dùng) bị giải phóng. Làm cho các đối tượng không được thống nhất và dẫn đến các lỗi không mong muốn, không an toàn khi sử dụng.
Bạn đã từng nghe nhiều về Multithreading. Ban đã biết về bộ xử lý Dual core của intel của AMD. Bạn biết rằng các công nghệ đó hỗ trợ việc xử lý song song...
Bạn có biết rằng bản thân ngôn ngữ Java cũng hỗ trợ Multithreading. Với bài viết này, tôi hi vọng sẽ giúp các bạn tìm hiểu sơ lược về Thread trong Java. Một lĩnh vực khá thú vị.
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 method : 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 :
PHP Code:
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 đã đặt 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 ko tạo được thread.
Hiện thực interface Runnable
Bạn khai báo như sau:
PHP Code:
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à: bạn 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
PHP Code:
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.
PHP Code:
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.
PHP Code:
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.
PHP Code:
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).
PHP Code:
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.
PHP Code:
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).
PHP Code:
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.
Chi tiết hơn bạn có thể xem ở Java API của bộ JDK
Một số phương thức chính của lớp Thread
PHP Code:
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.
PHP Code:
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.
PHP Code:
public final String getName()
- Phương thức này trả về tên của thread.
PHP Code:
public final void setName(String name)
- Thay đổi tên của thread bằng tên name.
PHP Code:
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ó.
PHP Code:
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.
PHP Code:
public static void sleep(long millis) throws InterruptedException
PHP Code:
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).
PHP Code:
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.
PHP Code:
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ó đã được khởi hoạt và chưa kết thúc công việc của nó.
PHP Code:
public final ThreadGroup getThreadGroup()
- Trả về nhóm Thread mà thread này thuộc về
PHP Code:
public final void join(long millis) throws InterruptedException
PHP Code:
public final void join(long millis, int nanos) throws InterruptedException
PHP Code:
public final void join() throws InterruptedException
- Đây là phương thức được gọi bởi một thread khác.
- Phương thức này làm cho thread gọi phải ngưng hoạt động và chờ trong một khoảng thời gian millis millisecond hoặc chờ trong khoảng thời gian millis millisecond và nanos nanosseconds, hoặc chờ cho đến khi thread này kết thúc thì mới tiếp tục hoạt động.
- Phương thức này có thể phát sinh một ngoại lệ InterruptedException nếu nó bị một thread khác làm ngưng hoạt động.
PHP Code:
public String toString()
- Trả về một thể hiện dạng String của thread này.
- Thể hiện này bao gồm tên, độ ưu tiên và nhóm.
PHP Code:
public final void stop()
PHP Code:
public final void stop(Throwable obj)
PHP Code:
public void destroy()
PHP Code:
public final void suspend()
PHP Code:
public final void resume()
- Các methods này đều được khuyến cáo là không nên dùng. Sẽ bị bỏ trong các phiên bản sau của bộ JRE và JDK.
- Bởi vì các methods này làm cho các monitor của hệ thống (được JVM tạo ra để giám sát các đối tượng của người dùng) bị giải phóng. Làm cho các đối tượng không được thống nhất và dẫn đến các lỗi không mong muốn, không an toàn khi sử dụng.
Đăng nhận xét