Trả lời câu hỏi của OP
Tôi có thể làm gì để đánh thức điều này đang chờ đợi một cách kỳ lạ mà không phải chờ đợi mãi mãi cho một sự kiện ngẫu nhiên?
, không có bất kỳ đánh thức giả nào có thể đánh thức chủ đề đang chờ này!
Cho dù wakeups giả mạo có thể hoặc không thể xảy ra trên một nền tảng cụ thể, trong một trường hợp của OP đoạn mã đó là tích cực không thể cho Condition.await()
trở lại và nhìn thấy dòng "giả wakeup!" trong luồng đầu ra.
Trừ khi bạn đang sử dụng Thư viện lớp Java rất kỳ lạ
Điều này là do tiêu chuẩn, OpenJDK 's ReentrantLock
' s phương pháp newCondition()
trả về AbstractQueuedSynchronizer
's thực hiện Condition
giao diện, lồng nhau ConditionObject
(bằng cách này, nó là việc thực hiện duy nhất của Condition
giao diện trong thư viện lớp này), và ConditionObject
' s phương pháp await()
tự kiểm tra xem tình trạng này không giữ và không có bất kỳ sự thức tỉnh giả nào có thể buộc phương pháp này quay trở lại nhầm.
Nhân tiện, bạn có thể tự kiểm tra vì nó khá dễ dàng để mô phỏng đánh thức giả sau khi AbstractQueuedSynchronizer
thực hiện dựa trên cơ sở.
AbstractQueuedSynchronizer
sử dụng LockSupport
các phương thức park
và unpark
phương thức cấp thấp và nếu bạn gọi LockSupport.unpark
một luồng đang chờ Condition
, hành động này có thể được phân biệt với một đánh thức giả.
Hơi tái cấu trúc đoạn trích của OP,
public class Spurious {
private static class AwaitingThread extends Thread {
@Override
public void run() {
Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
try {
cond.await();
System.out.println("Spurious wakeup!");
} catch (InterruptedException ex) {
System.out.println("Just a regular interrupt.");
}
} finally {
lock.unlock();
}
}
}
private static final int AMOUNT_OF_SPURIOUS_WAKEUPS = 10;
public static void main(String[] args) throws InterruptedException {
Thread awaitingThread = new AwaitingThread();
awaitingThread.start();
Thread.sleep(10000);
for(int i =0 ; i < AMOUNT_OF_SPURIOUS_WAKEUPS; i++)
LockSupport.unpark(awaitingThread);
Thread.sleep(10000);
if (awaitingThread.isAlive())
System.out.println("Even after " + AMOUNT_OF_SPURIOUS_WAKEUPS + " \"spurious wakeups\" the Condition is stil awaiting");
else
System.out.println("You are using very unusual implementation of java.util.concurrent.locks.Condition");
}
}
và cho dù luồng xử lý (chính) khó đến mức nào sẽ cố gắng đánh thức luồng đang chờ, Condition.await()
phương thức sẽ không bao giờ quay lại trong trường hợp này.
Các đánh thức giả về Condition
các phương thức chờ đợi được thảo luận trong javadoc của Condition
giao diện . Mặc dù nó nói rằng,
khi chờ đợi trong một Điều kiện, một sự thức tỉnh giả được phép xảy ra
và đó
khuyến cáo rằng các lập trình viên ứng dụng luôn cho rằng chúng có thể xảy ra và do đó luôn chờ trong một vòng lặp.
nhưng sau đó nói thêm rằng
Một triển khai là miễn phí để loại bỏ khả năng đánh thức giả
và AbstractQueuedSynchronizer
việc triển khai Condition
giao diện thực hiện chính xác điều đó - loại bỏ mọi khả năng đánh thức giả .
Điều này chắc chắn đúng với các ConditionObject
phương pháp chờ đợi khác.
Vì vậy, kết luận là:
chúng ta nên luôn luôn gọi Condition.await
trong vòng lặp và kiểm tra xem điều kiện không giữ, nhưng với tiêu chuẩn, OpenJDK, Thư viện lớp Java không bao giờ có thể xảy ra . Trừ khi, một lần nữa, bạn sử dụng Thư viện lớp Java rất khác thường (phải rất khác thường, bởi vì một Thư viện lớp Java không OpenJDK nổi tiếng khác, hiện gần như đã tuyệt chủng GNU Classpath và Apache Harmony , dường như giống hệt với triển khai Condition
giao diện chuẩn)
pthread_cond_wait()
câu hỏi thực sự là "Tại sao pthread_cond_wait có đánh thức giả?" .