Vấn đề tắc nghẽn trong Java

Cơ chế đồng bộ trong Java là rất tiện lợi, khá mạnh, nhưng không giải quyết dược mọi vấn đề nảy sinh trong quá trinh xử lý đa luồng. Ví dụ, hẵy xét tình huống: ở Account 1 có 2000$, Account 2 có 3000$ và luồng threadl cần chuyển 3000$ tù Account 1 sang Account 2, ngược lại thread2 phải chuyển 3500$ từ Account 2 sang Account 1. Khi dó, threadl và thread2 rơi vào tình trạng chết (ắc, hoặc tắc nghẽn vì chúng chặn lẫn nhau. Một hệ (hổng mà tẩt cả các luồng (tiến trình) bị chặn lại đê chờ lẫn nhau và không một luồng (tiến trình) nào thực hiện tiếp thì được gọi ỉà hệ thống bị chết tắc (tắc nghẽn). Trong tình huống ờ trên, cả hai luồng đều phải gọi wait () vì cà hai tài khoản đều không đù số tiền để chuyển đi. Hiện tượng chết tắc được mô tả như hình 1.5 dưới đây.

Trong chưorng trình SynBankTransfer. java, hiện tượng tắc nghẽn không xuất hiện bởi một lý do đon giản. Mỗi giao dịch chuyển tiền nhiều nhất là 10000$. Có 10 tài khoản với tổng số tiền là 100000$. Do đó, ờ mọi thời điểm đều có ít nhất một tài khoản có không ít hơn 10000$, nghĩa là luồng phụ trách tài khoản đó được phép thực hiện.

Tuy nhiên, khi lập trình ta có thể gây ra tình huống khác có thể làm xuất hiện tắc nghẽn, chẳng hạn trong SynBankTransfer. java thay vỉ gọi notifyAll () ta gọi notify (). Như ở trên đã phân tích, notifyAll () thông báo cho tất cả các luồng đang chờ nếu ở tài khoản có đù tiền chuyền đi thì có thể tiếp tục thực hiện, còn notify 0 chì báo cho một luồng được tiếp tục nếu có đù tiền chuyển đi. Khi đó, nếu luồng được thông báo lại không thể thực hiện, vi không đù tiền để chuyển chẳng hạn, thi tất cả các luồng khác cũng sẽ bj chặn lại. Chúng ta hãy xét kịch bản sau:

+ Account 1: 19000$

+ Tẩt cả các Account còn lại đều có 9000$

+ Thread 1: chuyển 9500$ từ Account 1 sang Account 2 + Tất luồng khác đều chuyển sang tài khoản khác một lượng tiền là 9100$.

Rõ ràng là chỉ có threadl đù tiền để chuyển còn các luồng khác bị chận lại threadl thực hiện chuyển tiền xong ta có:

+ Account 1: 9500$

+Account 2;18500$

+ Tất cả các Account còn lại đều có 9000$

Giả sử threadl gọi notify (). Hàm này chỉ thông báo cho một luồng ngẫu nhiên để nó có thể tiếp tục thực hiện. Giả sừ đó là thread3. Nhưng luồng này cũng không chuyển đuợc vì không đủ tiền ở tài khoản Account 3, nên phải chò (gọi wait ()). threadl vẫn tiếp tục thực hiện. Một giao dịch mới ngẫu nhiên lại được tạo ra.

Ví dụ,

Thread 1: chuyển 9600$ từ Account 1 sang Account 2.

Sau đó threadl gọi hàm wait (), và như vậy tất cả các luồng đều rcn vào tình trạng tắc nghẽn.

Qua ví dụ trên cho thấy, một ngôn ngữ lập trình cỏ ca chế hỗ trợ đồng bộ ìà chưa đủ để giải quyết vẩn đề tắc nghẽn. Quan trọng là khi thiết kế chương trình, ta phải đảm bảo rang ờ mọi thời điểm có ít nhất một luồng (tiến trình) được tiếp tục thực hiện và cố gắng không để xảy ra hiện tượng chết đồi, nghĩa là trạng thái mà ờ đó có một số luồng không bao giờ được tiếp tục thực hiện.