[Java] Tìm hiểu về Deadlock

Xin chào tất cả các bạn!

Lâu rồi mới có thời gian để viết tiếp bài về Java 😀 Topic này mình đã viết từ lâu nhưng bây giờ mới tiếp tục viết để hoàn thành. Vấn đề này mình nghĩ nhiều bạn cũng đang thắc mắc giống mình nên mình xin chia sẻ những gì mình biết về deadlock và cách để tránh gặp deadlock khi thực hiện xử lý multi-thread trong Java. Không phải dong dài nữa. Chúng ta cùng bắt đầu nào. Here we go!

Okie! Bắt đầu là Deadlock là gì?

Theo như docs từ Oracle thì

Deadlock describes a situation where two or more threads are blocked forever, waiting for each other.

Tạm dich là trạng thái khi mà 2 hoặc nhiều thread bị khóa vĩnh viễn và chờ đợi lẫn nhau kiểu như là “chờ người nơi ấy chờ quài không thấy” :D.

Nghe có vẻ phức tạp nhỉ, để mình mô tả cho nó rõ 1 chút:

  1. Deadlock xảy ra trong môi trường multi-thread (Tất nhiên rồi mà 😀 Có 1 thread thì độc quyền rồi cần gì phải đợi thằng nào nữa, thích thằng nào thì gọi thằng đó trả lời ngay lập tức)
  2. Khi có thread (1) đang giữ tài nguyên (A) và cần truy cập tài nguyên(B) để tiếp tục xử lý (call method xử lý…) nhưng tài nguyên (B) đang được thread (2) sử dụng, trong lúc này thì thread (2) cũng đang cần truy cập vào tài nguyên (A) mà thread (1) đang sử dụng. Lúc này thì cả 2 thread đều không thể tiếp tục thực hiện mà đều phải “chờ” nhau nhưng không biết khi nào thì sẽ kết thúc.
  3. Điều cuối cùng là deadlock xảy ra chúng ta sử dụng synchronization với mục đích đảm bảo thread-safe nhưng nếu không cẩn thận khi sử dụng lock-object (objectidentifier) thì sẽ dễ dẫn đến deadlock.

=> Nghe có vẻ xoắn não nhỉ 😀 Mình tìm thấy được ví dụ này trên stackoverflow khá là thú vị và dễ hiểu:

3XVzK

Image from stackoverflow: What is Deadlock?

Bây giờ mình sẽ giả sử qua code nhé:

public static Object Lock1 = new Object();
public static Object Lock2 = new Object();

public static void main(String args[]) {
Thread1 T1 = new Thread1();
Thread2 T2 = new Thread2();
T1.start();
T2.start();
}

private static class Thread1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Cop: Holding criminal's friend...");

try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Cop: Waiting for criminal release hostage...");

synchronized (Lock2) {
System.out.println("Cop 1: Holding criminal's friend & hostage...");
}
}
}
}
private static class Thread2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Criminal: Holding hostage...");

try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Criminal: Waiting for cop release friend...");
synchronized (Lock1) {
System.out.println("Criminal: Holding friend & hostage...");
}
}
}
}</pre>
<pre>

 

Console output:

Cop: Holding criminal's friend...
Criminal: Holding hostage...
Cop: Waiting for criminal release hostage...
Criminal: Waiting for cop release friend...

Tình hình có vẻ căng thẳng nhỉ! Cả 2 đều đang chờ nhau và không bên nào chịu thả con tin hay nói cách khác là mỗi “Lock” cần sử dụng đều đang bị thread khác chiếm giữ.

Để giải quyết trường hợp này. Chúng ta có 2 cách:

  1. Chỉ sử dụng 1 lock-object (objectidentifier) để synchronized tất cả các đoạn hoặc block code cần synchronization. (Trong ví dụ trên thì chỉ sử dụng Lock1 hoặc Lock2.  Nếu có thể thì không nên sử dụng cùng lúc 2 lock-object)
  2. Sử dụng lock-object (objectidentifier) theo thứ tự giống nhau với các block synchorined. Khi các lock-object được sử dụng để synchronization theo thứ tự thì sẽ ngăn được tình trạng các thread giữ nhiều “lock” khi thực hiện mà không cho phép thread khác sử dụng. (Tương tự ví dụ trên thì Thread1 synchronized với Lock1 & Lock thì Thread2 cũng synchronized với thứ tự Lock1 & Lock2)

Vậy cuối cùng là làm sao để nhận biết chúng ta đã gặp phải deadlock? Thường thì sẽ khó nhận biết deadlock khi mà chương trình của bạn lâu lâu bị “đơ” nhưng khi debug thì mọi thứ sẽ chạy đúng hoặc restart lại thì chương trình lại chạy bình thường, nói vậy nghĩa là deadlock không phải luôn luôn xảy ra mà là “thỉnh thoảng” nên cần phải phân tích code để tìm ra nguy cơ deadlock xảy ra ở đâu.

Tất cả là chia sẻ của mình về deadlock trong Java. Hi vọng sẽ giúp ích các bạn trong quá trình tìm hiểu về Java. Và mình cũng mong nhận được những comment hay góp ý của các bạn để hoàn thiện topic hơn nữa.

 

Advertisement

Share this:

Like this:

Like

Loading…