Jeff St
Jeff St

Reputation: 21

LinkedBlockingQueue.poll(...) occasionally throwing an InterruptedException

I'm using a java 1.8 java.util.concurrent.LinkedBlockingQueue, and when I call:

LinkedBlockingQueue.poll(5000, TimeUnit.MILLISECONDS)

it is very occasionally throwing an InterruptedException:

java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2088)
    at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)

which I think is happening because the following is returning true during the (indirect) call to checkInterruptWhileWaiting() at AbstractQueuedSynchronizer:2079

Unsafe.compareAndSwapInt(...) 

As a side note, Unsafe.compareAndSwapInt returns a boolean, but what does that boolean mean? I can't find any documentation on that Class/function.

I suspect that something is going on in another thread to cause this issue, but I'm not sure where to look right now.

Any help on understanding why the InterruptedException is being thrown would be very helpful. I would really like to be able to reproduce it in a small test program, but it's in a big messy program right now so I'm trying to understand what things could cause this so that I can create a test program to reproduce it.

Upvotes: 2

Views: 1225

Answers (1)

Tamas Rev
Tamas Rev

Reputation: 7166

Is there any other thread in your app that calls Thread.interrupt()? This is what's happening in awaitInNanos():

if (Thread.interrupted())
            throw new InterruptedException();

If you control the threads, then you can override the interrupt method just for testing:

    Thread thread = new Thread() {
        @Override
        public void run() {
            // do something longrunning
        }

        @Override
        public void interrupt() {
            // try-finally ensures to run both super.interrupt() and the deubg code 
            try {
                super.interrupt();
            } finally {
                // you can use any logging services that you already have
                System.out.println("--> Interrupted from thread: " + Thread.currentThread().getName());
                Thread.dumpStack();
            }
        }
    };

If you create the threads manually, you can override interrupt(). If you use executors, then you can provide a ThreadFactory, that creates the threads with the right interrupt() method.

Here is a main() method that plays with this debug technique. Please note that you need to enter a line in STDIN or manually kill the process. Otherwise it's going to run forever (jvm restart).

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            System.out.println("--> asdf");
            try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
                br.readLine();
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }

        }

        @Override
        public void interrupt() {
            // try-finally ensures to run both super.interrupt() and the deubg code 
            try {
                super.interrupt();
            } finally {
                // you can use any logging services that you already have
                System.out.println("--> Interrupted from thread: " + Thread.currentThread().getName());
                Thread.dumpStack();
            }
        }
    };
    thread.start();
    System.out.println("--> before interrupt");
    thread.interrupt();
    System.out.println("--> after interrupt");
}

Upvotes: 1

Related Questions