我有以下簡單的代碼,我在其中放入和取出表示為 ArrayList 的佇列。
public class EmailService {
private Queue<Email> emailQueue;
private Object lock;
private volatile boolean run;
private Thread thread;
public void sendNotificationEmail(Email email) throws InterruptedException {
emailQueue.add(email);
synchronized (lock) {
lock.notify();
lock.wait();
}
}
public EmailService() {
lock = new Object();
emailQueue = new Queue<>();
run = true;
thread = new Thread(new Runnable() {
@Override
public void run() {
while (run) {
System.out.println("ruuuning");
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (emailQueue.getSize() > 0) {
sendEmail(emailQueue.poll());
}
lock.notify();
}
}
}
private void sendEmail(Email email) {
System.out.println("Sent email from " email.getFrom() " to " email.getTo() " with content: " email.getContent());
}
});
thread.start();
}
public void close() throws InterruptedException {
run = false;
synchronized (lock) {
lock.notify();
System.out.println("Thread will join " thread.isInterrupted());
thread.join();
System.out.println("Thread after join");
}
}
}
我不明白為什么我的執行緒在join()方法中被阻塞。從主要我呼叫如下:
eService = new EmailService();
Email e1 = new Email(client1, client2, "content1");
eService.sendNotificationEmail(e1);
eService.close();
uj5u.com熱心網友回復:
不運行它...
- 該
close()方法lock在呼叫時保持thread.join()并等待thread(永遠) thread正在等待重新獲取lock所以無法運行
雙方現在都在互相等待,這是一個僵局。嘗試Thread.join()在synchronized塊之后移動:
public void close() throws InterruptedException {
run = false;
synchronized (lock) {
lock.notify();
System.out.println("Thread will join " thread.isInterrupted());
}
thread.join();
System.out.println("Thread after join");
}
uj5u.com熱心網友回復:
@drekbour 解釋了您的程式如何掛在join()呼叫中,但僅供參考:這是您的程式掛起的另一種方式。這稱為丟失通知。
您的主執行緒創建一個新EmailService實體。新實體創建其執行緒并呼叫thread.start()*BUT*執行緒實際開始運行可能需要一些時間。同時...
您的主執行緒創建一個新Email實體,并呼叫eService.sendNotificationEmail(...). 該函式將新訊息添加到佇列中,鎖定lock,通知鎖定,然后等待鎖定。
最后,服務執行緒啟動,進入它的run()方法,鎖定鎖,然后呼叫lock.wait()。
此時程式會卡住,因為每個執行緒都在等待對方的通知。
避免丟失通知的方法是,在消費者執行緒中,如果您正在等待的事情已經發生,則不要呼叫wait()。
synchronized(lock) {
while (theThingHasNotHappenedYet()) {
lock.wait();
}
dealWithTheThing();
}
在生產者執行緒中:
synchronized(lock) {
makeTheThingHappen();
lock.notify();
}
注意兩個執行緒如何鎖定鎖。有沒有想過lock.wait()如果鎖沒有鎖定為什么會拋出例外?上面的例子說明了原因。該鎖可防止生產者執行緒在消費者已經決定等待之后使事情發生。這是關鍵:如果消費者在生產者呼叫notify()之后等待,那么游戲就結束了。程式掛了。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/349302.html
