"Chào, Amigo!"

"Và một vài chi tiết nữa. Hãy gọi đó là lời khuyên thiết thực."

"Giả sử bạn có một phương pháp đang chờ một thứ gì đó và ngủ quên cho đến khi một điều kiện được thỏa mãn."

Nếu bộ sưu tập trống, thì chúng tôi đợi
public synchronized Runnable getJob()
{
 if (jobs.size() == 0)
  this.wait();

 return jobs.remove(0);
}

"Tài liệu Java rất khuyến nghị gọi phương thức chờ trong một vòng lặp:"

Nếu bộ sưu tập trống, thì chúng tôi đợi
public synchronized Runnable getJob()
{
 while (jobs.size() == 0)
  this.wait();

 return jobs.remove(0);
}

"Tại sao? Vấn đề là nếu sợi chỉ thức dậy, điều đó không có nghĩa là điều kiện đã thỏa mãn. Có lẽ có hai mươi sợi chỉ đang ngủ như vậy. Tất cả chúng đều thức dậy, nhưng chỉ một người có thể nhận nhiệm vụ."

"Nói một cách đại khái, có thể có 'báo động sai'. Một nhà phát triển giỏi phải tính đến điều này."

"Tôi hiểu rồi. Không phải sử dụng thông báo sẽ dễ dàng hơn sao?"

"Chà, nếu có nhiều hơn một nhiệm vụ trong danh sách thì sao? Thông báo thường được khuyến nghị sử dụng vì mục đích tối ưu hóa. Trong tất cả các trường hợp khác, bạn nên sử dụng phương thức notifyAll."

"ĐƯỢC RỒI."

"Nhưng còn nhiều hơn nữa. Đầu tiên, có thể xảy ra trường hợp ai đó kế thừa lớp của bạn, thêm các phương thức của riêng họ và cũng sử dụng wait/notifyAll. Nói cách khác, có thể xảy ra trường hợp các cặp wait/notifyAll độc lập chờ trên cùng một đối tượng và không biết về nhau. Vậy bạn nên làm gì?"

"Luôn gọi đợi trong một vòng lặp và kiểm tra xem điều kiện kết thúc của vòng lặp có đúng không!"

"Phải. Và để làm rõ rằng bạn không thể thoát khỏi điều này, nhiều nhà phát triển chỉ ra rằng đôi khi các luồng tự đánh thức. Các luồng được đảm bảo không bị đánh thức một cách tình cờ. Đây dường như là tác dụng phụ của việc tối ưu hóa mã trong một chạy máy Java."

"Ồ. Hiểu rồi. Không có vòng lặp, phương pháp chờ đợi là không tốt."