Java Concurrency - Bế tắc
Deadlock mô tả một tình huống mà hai hoặc nhiều luồng bị chặn mãi mãi, chờ đợi nhau. Chốt lại xảy ra khi nhiều luồng cần các khóa giống nhau nhưng lấy chúng theo thứ tự khác nhau. Một chương trình đa luồng Java có thể gặp phải tình trạng deadlock vìsynchronizedtừ khóa khiến luồng thực thi bị chặn trong khi chờ khóa hoặc giám sát, được liên kết với đối tượng được chỉ định. Đây là một ví dụ.
Thí dụ
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
Khi bạn biên dịch và thực thi chương trình trên, bạn thấy một tình huống bế tắc và sau đây là kết quả do chương trình tạo ra:
Đầu ra
Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...
Chương trình trên sẽ treo vĩnh viễn vì không có luồng nào ở vị trí để tiến hành và chờ nhau giải phóng khóa, vì vậy bạn có thể thoát khỏi chương trình bằng cách nhấn CTRL + C.
Ví dụ về giải pháp bế tắc
Hãy thay đổi thứ tự của khóa và chạy cùng một chương trình để xem liệu cả hai chủ đề có còn chờ nhau không -
Thí dụ
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
Vì vậy, chỉ cần thay đổi thứ tự của các khóa ngăn chương trình rơi vào tình trạng bế tắc và hoàn thành với kết quả sau:
Đầu ra
Thread 1: Holding lock 1...
Thread 1: Waiting for lock 2...
Thread 1: Holding lock 1 & 2...
Thread 2: Holding lock 1...
Thread 2: Waiting for lock 2...
Thread 2: Holding lock 1 & 2...
Ví dụ trên chỉ là làm rõ khái niệm, tuy nhiên, đây là một khái niệm phức tạp và bạn nên tìm hiểu sâu về nó trước khi phát triển các ứng dụng của mình để giải quyết các tình huống bế tắc.