2
votes

In the example below I am attempting to gracefully terminate both threads. The consumer thread gets interrupted while sleeping, which should set the isInterrupted flag to true. However the !Thread.currentThread().isInterrupted() check on the while loop still seems to return = false because it does not terminate the consumer thread.

Copy and paste the code below into and IDE to check:

public class ThreadInterruptExample {

public static void main(String[] args) throws InterruptedException {
    LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(1);
    ThreadInterruptExample ie = new ThreadInterruptExample();
    Producer producer = ie.new Producer(queue);
    Consumer consumer = ie.new Consumer(queue, producer);
    producer.start();
    consumer.start();
    Thread.sleep(1000);
    producer.cancel();
    consumer.cancel();
}

class BaseQueue extends Thread {
    protected final BlockingQueue<String> queue;

    public BaseQueue(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    public void cancel() {
        System.out.println(this.getName() + " - Shutting down");
        interrupt();
    }
}

class Producer extends BaseQueue {
    private final List<String> messages = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q",
            "r", "s", "t", "u", "v", "w", "x", "y", "z");

    public Producer(BlockingQueue<String> queue) {
        super(queue);
        this.setName("Producer");
    }

    public void run() {
        try {
            for (String message : messages) {
                System.out.println(this.getName() + ": Sending " + message);
                queue.put(message);
            }
        } catch (InterruptedException e) {
            System.out.println(this.getName() + " - InterruptedException occurred");
        }
    }
}

class Consumer extends BaseQueue {
    private final BaseQueue producer;

    public Consumer(BlockingQueue<String> queue, BaseQueue producerQueue) {
        super(queue);
        this.setName("Consumer");
        producer = producerQueue;
    }

    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println(this.getName() +": Consumer Running");
            String message = "";
            try {
                Thread.sleep(1500);
                message = queue.take();
                System.out.println(this.getName() + ": Recevied " + message);
                if (message.equals("pill")) {
                    producer.cancel();
                    this.cancel();
                }
            } catch (InterruptedException e) {
                System.out.print(this.getName() + ": Exception occurred for: " + message);
                e.printStackTrace();
            }
        }
    }

}

}

2

2 Answers

5
votes

You are discarding the interrupt when you catch the InterruptedException. There is two solutions.

while (!Thread.currentThread().isInterrupted()) {
    try {
        Thread.sleep(1500);

    } catch (InterruptedException e) {
        Thread.currentThread.interrupt();
    }
}

or much simpler is to only catch the Exception outside the loop.

try {
    while (!Thread.currentThread().isInterrupted()) {
        Thread.sleep(1500);
    }
} catch (InterruptedException e) {
    Thread.currentThread.interrupt();
}

EDIT: I assume this is just an exercise as it would be far simpler to use an ExecutorService

public static void main(String[] args) throws InterruptedException {
    ExecutorService service = Executors.newSingleThreadExecutor();

    for (String message : "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z".split(",")) {
        System.out.println(getThreadName() + ": Sending " + message);
        service.submit(() -> {
            System.out.println(getThreadName() + ": Recevied " + message);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                System.out.println("--- Interrupted");
            }
        });
    }
    service.shutdown();
    service.awaitTermination(1, TimeUnit.SECONDS);
    service.shutdownNow();
}

public static String getThreadName() {
    return Thread.currentThread().getName();
}

prints

main: Sending a
main: Sending b
main: Sending c
main: Sending d
main: Sending e
main: Sending f
main: Sending g
main: Sending h
main: Sending i
main: Sending j
main: Sending k
main: Sending l
main: Sending m
main: Sending n
main: Sending o
main: Sending p
main: Sending q
main: Sending r
main: Sending s
main: Sending t
main: Sending u
main: Sending v
main: Sending w
main: Sending x
main: Sending y
main: Sending z
pool-1-thread-1: Recevied a
pool-1-thread-1: Recevied b
--- Interrupted
1
votes

As indicated in the javadocs

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

So in your case as the consumer is sleeping while interrupt was called, the interrupt status is cleared and you received an InterruptedException where you can decide what to do next.