1
votes

I have a thread pool with fixed number of working threads (say 4). I continiously fetch new runnables to an executor. All of these runnables have a long period sleep call, waiting for another thread to be interrupted by it:

Runnable runnable =  new Runnable() {
    @Override
    public void run() {
        //do preparation
        doPreWork();

        //wait for some other runnable to interrupt me
        try {
            Thread.sleep(40000);
        }
        catch(InterruptedException e) {
        }

        //finish work
        doAfterWork();
    }                   
}

So the question is: when I fetch first 4 runnables to my executor, all working threads are sleeping and other incoming runnables(a lot of them, because they are continiously incoming) are queued and have to wait for available threads. Is there any way, I can use sleeping threads to execute new incoming runnables, maintaining others sleeping?

2
I don't understand the question. If your tasks call sleep then the thread that is running it can't do anything else. If another task is submitted it will either start another thread or wait depending on the type of ExecutorService being used. - Gray
@Gray, The problem is I don't want to create a new thread for each runnable, because there woudl be thousands of them. How can I design it, so queued runnbales don't wait? - Valera
Thread.sleep() is useful when; (a) you want to force a particular interleaving of threads for demo purposes (e.g., to reveal a concurrency bug), (b) you want to re-invent the wheel, and write your own scheduler, or (c) as a really hacky way to slow down a loop in a single-threaded program. Explicitly calling Thread.sleep() in any serious, multi-threaded software is usually a bad choice. - Solomon Slow

2 Answers

2
votes

No, a sleeping thread is sleeping. You can't make it do something else.

What you should do is add a scheduled task which is delayed by the amount of time you want. This will free up the current thread and allow it to do something else.

ScheduledExecutorService ses = ...

ses.submit(new Runnable() {
    @Override
    public void run() {
        //do preparation
        doPreWork();

        ses.schedule(new Runnable() {
            @Override
            public void run() {
                //finish work
                doAfterWork();
            }
        }, 40000);
    }                   
}

IMHO, Sending signals via interrupts is very unreliable. Don't write code which depends on it.

0
votes

I'm not exactly sure on the syntax, but you could look at a callback timer. So for example, you split your run() method into two parts, preWork and postWork. Once you have done the preWork, you add the object to a list/map/queue etc, with a 'comeToLife' value. Your thread would then look at this queue, find a different object whose 'comeToLife' time had already been reached, and call the postWork.

You should really be using a Lock or some other mechanism if you need your threads to run as soon as they are interrupted, because the InterruptException will not always get called...