Java Concurrency - Tổng quan
Java là một ngôn ngữ lập trình đa luồng có nghĩa là chúng ta có thể phát triển chương trình đa luồng bằng Java. Một chương trình đa luồng chứa hai hoặc nhiều phần có thể chạy đồng thời và mỗi phần có thể xử lý một tác vụ khác nhau cùng lúc để sử dụng tối ưu các tài nguyên có sẵn, đặc biệt khi máy tính của bạn có nhiều CPU.
Theo định nghĩa, đa nhiệm là khi nhiều quy trình chia sẻ tài nguyên xử lý chung như CPU. Đa luồng mở rộng ý tưởng về đa nhiệm vào các ứng dụng nơi bạn có thể chia nhỏ các hoạt động cụ thể trong một ứng dụng thành các luồng riêng lẻ. Mỗi luồng có thể chạy song song. Hệ điều hành phân chia thời gian xử lý không chỉ giữa các ứng dụng khác nhau mà còn giữa từng luồng trong một ứng dụng.
Đa luồng cho phép bạn viết theo cách mà nhiều hoạt động có thể tiến hành đồng thời trong cùng một chương trình.
Vòng đời của một sợi chỉ
Một luồng trải qua nhiều giai đoạn khác nhau trong vòng đời của nó. Ví dụ, một luồng được sinh ra, bắt đầu, chạy và sau đó chết. Sơ đồ sau đây cho thấy toàn bộ vòng đời của một luồng.
Sau đây là các giai đoạn của vòng đời:
New- Một luồng mới bắt đầu vòng đời của nó ở trạng thái mới. Nó vẫn ở trạng thái này cho đến khi chương trình bắt đầu luồng. Nó cũng được gọi làborn thread.
Runnable- Sau khi một luồng mới sinh được bắt đầu, luồng đó có thể chạy được. Một luồng ở trạng thái này được coi là đang thực thi nhiệm vụ của nó.
Waiting- Đôi khi, một luồng chuyển sang trạng thái chờ trong khi luồng đó chờ một luồng khác thực hiện một tác vụ. Một luồng chỉ chuyển trở lại trạng thái chạy được khi một luồng khác báo hiệu luồng đang chờ tiếp tục thực thi.
Timed Waiting- Một luồng có thể chạy được có thể vào trạng thái chờ được hẹn giờ trong một khoảng thời gian nhất định. Một luồng ở trạng thái này chuyển trở lại trạng thái có thể chạy khi khoảng thời gian đó hết hạn hoặc khi sự kiện mà nó đang chờ xảy ra.
Terminated (Dead) - Một luồng có thể chạy đi vào trạng thái kết thúc khi nó hoàn thành nhiệm vụ của nó hoặc kết thúc bằng cách khác.
Ưu tiên chuỗi
Mỗi luồng Java đều có một mức độ ưu tiên giúp hệ điều hành xác định thứ tự mà các luồng được lập lịch.
Mức độ ưu tiên của luồng Java nằm trong phạm vi giữa MIN_PRIORITY (hằng số 1) và MAX_PRIORITY (hằng số 10). Theo mặc định, mọi luồng được ưu tiên NORM_PRIORITY (hằng số 5).
Các luồng có mức độ ưu tiên cao hơn quan trọng hơn đối với một chương trình và nên được phân bổ thời gian xử lý trước các luồng có mức độ ưu tiên thấp hơn. Tuy nhiên, các ưu tiên của luồng không thể đảm bảo thứ tự mà các luồng thực thi và phụ thuộc rất nhiều vào nền tảng.
Tạo một chuỗi bằng cách triển khai một giao diện có thể chạy được
Nếu lớp của bạn dự định được thực thi dưới dạng một luồng thì bạn có thể đạt được điều này bằng cách triển khai Runnablegiao diện. Bạn sẽ cần làm theo ba bước cơ bản -
Bước 1
Bước đầu tiên, bạn cần triển khai phương thức run () được cung cấp bởi Runnablegiao diện. Phương thức này cung cấp một điểm vào cho luồng và bạn sẽ đưa logic nghiệp vụ hoàn chỉnh của mình vào bên trong phương pháp này. Sau đây là một cú pháp đơn giản của phương thức run ():
public void run( )
Bước 2
Bước thứ hai, bạn sẽ khởi tạo Thread đối tượng sử dụng hàm tạo sau:
Thread(Runnable threadObj, String threadName);
Trong đó, threadObj là một thể hiện của một lớp thực hiệnRunnable giao diện và threadName là tên được đặt cho chủ đề mới.
Bước 3
Sau khi một đối tượng Thread được tạo, bạn có thể bắt đầu nó bằng cách gọi start()phương thức thực thi một cuộc gọi đến phương thức run (). Sau đây là một cú pháp đơn giản của phương thức start ():
void start();
Example
Đây là một ví dụ tạo một chuỗi mới và bắt đầu chạy nó -
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo("Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo("Thread-2");
R2.start();
}
}
Điều này sẽ tạo ra kết quả sau:
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Tạo một chủ đề bằng cách mở rộng một lớp chủ đề
Cách thứ hai để tạo một luồng là tạo một lớp mới mở rộng Threadlớp bằng hai bước đơn giản sau. Cách tiếp cận này cung cấp sự linh hoạt hơn trong việc xử lý nhiều luồng được tạo bằng các phương thức có sẵn trong lớp Thread.
Bước 1
Bạn sẽ cần ghi đè run( )phương thức có sẵn trong lớp Thread. Phương thức này cung cấp một điểm vào cho luồng và bạn sẽ đưa logic nghiệp vụ hoàn chỉnh của mình vào bên trong phương pháp này. Sau đây là một cú pháp đơn giản của phương thức run ():
public void run( )
Bước 2
Sau khi đối tượng Thread được tạo, bạn có thể bắt đầu nó bằng cách gọi start()phương thức thực thi một cuộc gọi đến phương thức run (). Sau đây là một cú pháp đơn giản của phương thức start ():
void start( );
Example
Đây là chương trình trước đó được viết lại để mở rộng Chủ đề -
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo("Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo("Thread-2");
T2.start();
}
}
Điều này sẽ tạo ra kết quả sau:
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.