目前我一直在使用
FixedThreadPool
来细分一个大任务;这一切都运行良好。然而;我现在发现其中一项任务的一部分本身可以细分。我曾经尝试向 FixedThreadPool
提交更多 Callables,但程序挂在 Future#get()
上(在代码中标记)
以下程序复制了该问题(我使用了尺寸为 1 的
FixedThreadPool
使问题变得更糟)
public class ThreadPoolTest {
static ExecutorService threadPool=Executors.newFixedThreadPool(1);
//method run by inner callable
public void printText(){
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadPoolTest.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("Printed from within thread");
}
//method run by outer callable
public void testThreadPool(){
Callable<Void> printOnAThread=()->{printText(); return null; };
Future<Void> f2=threadPool.submit(printOnAThread);
try {
System.out.println("Called");
f2.get(); //<--hangs here
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(ThreadPoolTest.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException("Failed to print in thread", ex);
}
}
public static void testThreadWithinThread(){
ThreadPoolTest t=new ThreadPoolTest();
Callable<Void> testCallable=()->{t.testThreadPool();return null;};
Future<Void> f=threadPool.submit(
testCallable
);
try {
f.get();
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(ThreadPoolTest.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException("Main thread failed", ex);
}
}
public static void main(String[] args){
testThreadWithinThread();
threadPool.shutdown();
System.out.println("Program exits");
}
}
testThreadWithinThread()
奔跑testThreadWithinThread()
提交可调用 (()->{t.testThreadPool();return null;};
)testThreadPool();
本身提交了一个内部可调用的()->{printText(); return null; };
f.get();
,外部可调用块并等待。这会释放 FixedThreadPool
f2.get();
不再阻塞,外部可调用运行至完成步骤 1-6 正如我预期的那样发生,但是在第 7 点,外部可调用对象被阻止;由于某种原因,它没有释放线程,因此程序挂起。
为什么程序此时挂起?有什么方法可以安全地从可调用对象中提交可调用对象吗?
您的线程池包含 1 个线程。它一次只能执行一个可调用/可运行。所有其他提交的任务都会排队,直到有线程可以执行它们为止。
增加泳池大小。
我目前正在自己解决同样的问题,我将在尝试这个问题时给出一些我的观察结果......
您可以创建 Callable 的包装对象,其中包含对 ExecutorService 的引用。现在,您可以让该 Callable 也向 ExecutorService 提交一个新的 Callable。
如果父 Callable 不依赖于子 Callable 的完成,那么这实际上与使用两个完全不相关的构造将 Callable 提交到同一个 ExecutorService 引用没有什么不同。 ExecutorService 最终将完成这两个任务 - 一切如常。
但是,如果其中一些 Callable 等待(即在返回的
.get()
上调用 Future<V>
)他们已提交的 Callable,事情会变得更加复杂。因为显然你现在有一个线程正在等待另一个线程完成。这本质上并不是一个糟糕的情况,但它取决于很多因素......每个 Callable 需要多长时间?你将有多少个线程?线程可以有超时吗?您需要处理的传入有效负载量是多少?
例如,2 个线程,三个级联 Callable:
你现在面临的是教科书般的僵局。