Java Thread Pools/Executor Service and wait()s - 线程和任务队列会发生什么变化?

我环顾四周,但没有找到答案,所以我想确认这一点。

假设我有一个固定大小的线程池 -ExecutorService pool = Executors.newFixedThreadPool(5);

我有一些代码:

pool.execute(new Runnable(){
    try{
        Object waitForMe = doSomethingAndGetObjectToWaitFor();
        waitForMe.wait();
        doSomethingElse();
    }catch(Exception e){ throw new RunTimeException(e) } 

});

让我们假设上面的代码被调用了几次100次。池中只有 5 个线程(因此上述语句中只有 5 个应该在某一点上处于活动状态)。还假设 正在一个对象上对第三方执行一些 I/O 调用,并在操作完成时等待回调,因此自然需要一段时间才能完成。wait()

现在我的问题是,当其中一个任务到达时,行为是什么,任务是否进入睡眠状态,然后线程池中的线程将另一个任务从队列中取出并开始运行它?wait()

如果正在等待的任务进入睡眠状态,那么当它到达并唤醒时会发生什么?线程是否返回到线程池的队列(在前面或后面)并等到5个线程中的一个可以继续执行它(即调用)?或者执行它的线程是否也进入睡眠状态,即5个执行器线程中的一个等待任务(这是我的假设)?或者执行器线程是否拾取另一个任务,并在第一个任务从 wait() 返回时被中断?notify()doSomethingelse()


答案 1

wait() 是一个阻塞操作:

使当前线程等待,直到另一个线程调用 notify() 方法或 notifyAll()

这意味着池中的线程将等待,但从外部看,当前任务需要很长时间才能完成。这也意味着,如果执行了 5 个任务,并且它们全部执行,则 无法处理在队列中等待的剩余任务。wait()Executor

没错,执行器线程本身进入休眠状态,允许其他线程切换并消耗CPU(因此您可以同时等待数百个线程,并且您的系统仍然响应),但线程仍然“不可用”并被阻止。

另一个有趣的功能是中断 - 如果线程等待某些东西或睡眠,你可以中断它。请注意,Thread.sleep() 都声明了 InterruptedException。使用 ExecutorService,您只需调用:future.cancel() (是您在向 其提交任务时返回的对象)来利用这一点。wait()futureExecutorService

最后,我认为您应该重新设计您的解决方案。与其主动等待外部系统完成,不如提供带有回调的 API:

pool.execute(new Runnable(){
    try{
        doSomethingAndCallMeBackWhenItsDone(new Callback() {
            public void done() {
                doSomethingElse();
            }
        });
    }catch(Exception e){ throw new RunTimeException(e) } 

});

这样,外部系统的API将在结果准备就绪时简单地通知您,您不必等待并阻止 。最后,如果花费大量时间,您甚至可能决定安排它,而不是使用外部第三方 I/O 线程:ExecutorServicedoSomethingElse()

pool.execute(new Runnable(){
    try{
        doSomethingAndCallMeBackWhenItIsDone(new Callback() {
            public void done() {
                pool.submit(new Callbale<Void>() {
                    public Void call() {
                        doSomethingElse();
                    }
                }
            }
        });
    }catch(Exception e){ throw new RunTimeException(e) } 

});

更新:您正在询问如何处理超时?这是我的想法:

pool.execute(new Runnable(){
    try{
        doSomethingAndCallMeBackWhenItsDone(new Callback() {
            public void done() {
                doSomethingElse();
            }
            public void timeout() {
                //opps!
            }
        });
    }catch(Exception e){ throw new RunTimeException(e) } 

});

我想你可以在第三方端实现超时,如果超时发生,只需调用方法。timeout()


答案 2

对踏脚池一无所知。线程池无法知道有关 .所以他们无论如何都不能互动。wait()wait()

它们像往常一样工作 - 只是一个长时间运行的阻塞操作,线程池只是一个在有限的线程池上运行的runnables队列。wait()


推荐