Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make my generics code compatible with this method signature?

Tags:

java

generics

I have a variation of the following code:

package com.test.package;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestClass {

    public static class MyRunnable implements Runnable {

        @Override
        public void run() {
            System.out.println("Called");
        }

    }

    public void method() {
        PriorityBlockingQueue<MyRunnable> queue = new PriorityBlockingQueue<MyRunnable>();
        method2(queue);
    }

    public void method2(BlockingQueue<? extends Runnable> queue) {
        System.out.println(queue);

        // Getting error here because BlockingQueue<? extends Runnable> is not a
        // subtype of BlockingQueue<Runnable>.
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(200, 200, 0L,
            TimeUnit.MILLISECONDS, queue);
    }
}

And as you can see, my queue is not compatible with the ThreadPoolExecutor constructor. Is there any way to work around this than cast my queue to (BlockingQueue<Runnable>)? I obviously can't patch Java Standard Library.

like image 484
Ztyx Avatar asked Jul 08 '14 15:07

Ztyx


1 Answers

No, and you shouldn't.

Your BlockingQueue<MyRunnable> should, of course, only contain MyRunnables. But the ThreadPoolExecutor can submit arbitrary Runnable tasks to the queue you give it: see execute(Runnable command).

If that happens, you could have a non-MyRunnable instance in your queue. You then try to poll from your reference of that queue (typed as a BlockingQueue<MyRunnable>), and get a ClassCastException.

Simple example:

PriorityBlockingQueue<MyRunnable> queue = new PriorityBlockingQueue<>();
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(200, 200, 0L,
        TimeUnit.MILLISECONDS, queue);
threadPool.execute(new WhateverRunnable());
MyRunnable myRunnable = queue.poll(); // this could throw ClassCastException

The above code will throw an exception if the queue.poll() happens before the thread pool has had a chance to dequeue the WhateverRunnable instance.

like image 92
yshavit Avatar answered Oct 31 '22 15:10

yshavit