Java 线程在 join() 中被阻塞
Java Thread is blocked in join()
我有以下简单代码,我在其中放入和取出表示为 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()
方法中被阻塞。
从 main 我调用如下:
eService = new EmailService();
Email e1 = new Email(client1, client2, "content1");
eService.sendNotificationEmail(e1);
eService.close();
@drekbour 解释了您的程序如何在 join()
调用中挂起,但仅供参考:这是您的程序可能挂起的 不同 方式。这称为丢失通知。
您的主线程创建了一个新的 EmailService
实例。新实例创建它的线程并调用 thread.start()
*但是*它 可能 需要一些时间让线程真正启动 运行。同时...
您的主线程创建一个新的 Email
实例,并调用 eService.sendNotificationEmail(...)
。该函数将新消息添加到队列,锁定 lock
,通知锁,然后等待锁。
最后,服务线程启动,进入它的run()
方法,锁上锁,然后调用lock.wait()
.
此时程序会卡住,因为每个线程都在等待对方的通知。
避免丢失通知的方法是,在消费者线程中,如果您正在等待的事情已经发生,则不要调用wait()
。
synchronized(lock) {
while (theThingHasNotHappenedYet()) {
lock.wait();
}
dealWithTheThing();
}
在生产者线程中:
synchronized(lock) {
makeTheThingHappen();
lock.notify();
}
注意两个线程是如何锁定锁的。有没有想过为什么 lock.wait()
如果锁没有被锁定会抛出异常?上面的例子说明了原因。锁可以防止生产者线程在消费者已经决定等待之后让事情发生。这很关键:如果消费者在生产者调用 notify()
之后等待,那么游戏就结束了。程序挂了。
没有 运行宁它...
close()
方法在调用 thread.join()
时保持 lock
并等待 thread
(永远)
thread
正在等待重新获取 lock
,所以不能 运行
现在双方都在互相等待,这是一个deadlock。尝试将 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");
}
我有以下简单代码,我在其中放入和取出表示为 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()
方法中被阻塞。
从 main 我调用如下:
eService = new EmailService();
Email e1 = new Email(client1, client2, "content1");
eService.sendNotificationEmail(e1);
eService.close();
@drekbour 解释了您的程序如何在 join()
调用中挂起,但仅供参考:这是您的程序可能挂起的 不同 方式。这称为丢失通知。
您的主线程创建了一个新的 EmailService
实例。新实例创建它的线程并调用 thread.start()
*但是*它 可能 需要一些时间让线程真正启动 运行。同时...
您的主线程创建一个新的 Email
实例,并调用 eService.sendNotificationEmail(...)
。该函数将新消息添加到队列,锁定 lock
,通知锁,然后等待锁。
最后,服务线程启动,进入它的run()
方法,锁上锁,然后调用lock.wait()
.
此时程序会卡住,因为每个线程都在等待对方的通知。
避免丢失通知的方法是,在消费者线程中,如果您正在等待的事情已经发生,则不要调用wait()
。
synchronized(lock) {
while (theThingHasNotHappenedYet()) {
lock.wait();
}
dealWithTheThing();
}
在生产者线程中:
synchronized(lock) {
makeTheThingHappen();
lock.notify();
}
注意两个线程是如何锁定锁的。有没有想过为什么 lock.wait()
如果锁没有被锁定会抛出异常?上面的例子说明了原因。锁可以防止生产者线程在消费者已经决定等待之后让事情发生。这很关键:如果消费者在生产者调用 notify()
之后等待,那么游戏就结束了。程序挂了。
没有 运行宁它...
close()
方法在调用thread.join()
时保持lock
并等待thread
(永远)thread
正在等待重新获取lock
,所以不能 运行
现在双方都在互相等待,这是一个deadlock。尝试将 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");
}