我环顾四周但没有找到答案,所以我想确认一下 .
假设我有一个固定大小的线程池 - ExecutorService pool = Executors.newFixedThreadPool(5);
我有一些代码:
pool.execute(new Runnable(){
try{
Object waitForMe = doSomethingAndGetObjectToWaitFor();
waitForMe.wait();
doSomethingElse();
}catch(Exception e){ throw new RunTimeException(e) }
});
让我们假设上面的代码被称为几百次 . 池中只有5个线程(因此上述语句中只有5个应该在一个点上存在) . 还假设 wait()
在一个对象上,对一个thrid方进行一些I / O调用,并在操作完成时等待回调,因此它自然需要一段时间才能完成 .
现在我的问题是当其中一个任务到达 wait()
时的行为是什么,该任务是否进入休眠状态,然后线程池中的线程将另一个任务从队列中取出并开始运行它?
如果等待的任务进入睡眠状态,当它获得 notify()
并醒来时会发生什么?线程是否返回到线程池的队列(前面或后面)并等待,直到5个线程中的一个可以继续执行它(即调用 doSomethingelse()
)?或者正在执行它的线程是否也进入休眠状态,即5个执行程序线程中的一个正在等待任务(这是我假设的)?或者执行程序线程是否接受另一个任务,并在第一个任务从wait()返回时被中断?
4 回答
wait()是一个阻塞操作:
这意味着池中的线程将等待,但从外部看起来当前任务需要花费很多时间才能完成 . 这也意味着如果执行5个任务并且它们都是
wait()
,则Executor
无法处理剩余的任务,ekhem在队列中等待 .确实,执行程序线程本身进入休眠状态,允许其他线程切换并消耗CPU(因此您可以让数百个线程同时等待并且您的系统仍然响应)但仍然线程“无法使用”并被阻止 .
另一个有趣的功能是中断 - 如果线程等待某事或睡眠,你可以打断它 . 请注意,
wait()
和Thread.sleep()都声明InterruptedException . 使用ExecutorService,您可以通过简单地调用来利用它:future.cancel()(future
是将任务提交到ExecutorService
时获得的对象) .最后我想你应该重新设计你的解决方案 . 而不是主动等待外部系统完成,提供带回调的API:
这样外部系统's API will simply notify you when the results are ready and you won' t必须等待并阻止
ExecutorService
. 最后,如果doSomethingElse()
需要花费很多时间,您甚至可能决定安排它,而不是使用外部第三方I / O线程:更新:您在询问如何处理超时?这是我的想法:
我想你可以在第三方实现超时,如果在那里发生超时,只需调用
timeout()
方法 .wait()
对胎面池一无所知 . 并且线程池对wait()
一无所知 . 所以无论如何他们都无法互动 .它们像往常一样工作 -
wait()
只是一个长时间运行的阻塞操作,线程池只是在有限的线程池上运行的runnables队列 .我会评论Tomasz的答案,但我的声誉不允许(还),抱歉 .
我知道这个问题已经过时了,但对于那些仍然最终阅读本页的人来说,看看Future,特别是guava的ListenableFuture,它可以让你注册回调和链接未来,恰恰是不阻塞你的线程的目的(和从而将线程释放回池中以供其他人使用它 .
将阻止所有5个线程,并且应用程序将处于非 生产环境 状态 .
添加到 Tomasz 回答,我想实现如下的超时机制 .
除了
TimeoutException
,您可以在InterruptedException & ExecutionException
期间取消Future . 如果使用submit()而不是execute(),则InterruptedException & ExecutionException
将在框架本身中被吞下 .