简体   繁体   中英

Java Thread is blocked in join()

I have the following simple code in which I put and take from a Queue represented as an 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");
        }
    }
}

I don't understand why my thread is blocked in join() method. From main I call as follow:

eService = new EmailService();
Email e1 = new Email(client1, client2, "content1");
eService.sendNotificationEmail(e1);
eService.close();

Without running it...

  • The close() method holds lock at the time it calls thread.join() and waits on thread (forever)
  • thread is waiting to reacquire lock so cannot run

Both are now waiting on each other, this is a deadlock . Try moving the Thread.join() after the synchronized block:

    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");
    }

@drekbour explained how your program could hang in the join() call, but FYI: Here's a different way that your program could hang. This is called lost notification.

Your main thread creates a new EmailService instance. The new instance creates its thread and calls thread.start() *BUT* it could take some time for the thread to actually start running. Meanwhile...

Your main thread creates a new Email instance, and calls eService.sendNotificationEmail(...) . That function adds the new message to the queue, locks the lock , notifies the lock, and then waits on the lock.

Finally, The service thread starts up, enters its run() method, locks the lock, and then it calls lock.wait() .

At this point, the program will be stuck because each thread is waiting to be notified by the other.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM