将可调用的可调用内容提交给Executor服务会导致程序挂起

时间:2014-05-15 21:37:18

标签: java multithreading threadpool

目前我一直使用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");
    }
}

我期望发生什么

  1. 提交第一个帖子。 testThreadWithinThread()运行
  2. testThreadWithinThread()提交Callable(()->{t.testThreadPool();return null;};
  3. 提交的callable开始运行&#34;立即&#34;
  4. t.testThreadPool();开始运行
  5. testThreadPool();本身提交内部可调用()->{printText(); return null; };
  6. 内部可调用无法运行,因为线程池不是
  7. 到达
  8. f.get();,外部可调用块并等待。这将释放FixedThreadPool
  9. 中的线程
  10. 内部可调用现在运行完成
  11. f2.get();不再被阻止,外部可调用运行完成
  12. 实际发生了什么

    步骤1-6按照我的预期发生,但在第7点时外部可调用被阻止;由于某种原因,它不会释放线程,因此程序会挂起。

    问题

    为什么程序在此时挂起?有什么方法可以安全地从callables中提交callables吗?

1 个答案:

答案 0 :(得分:2)

您的线程池包含1个线程。它一次只能执行一个可调用/可运行。所有其他提交的任务都排队,直到有一个线程可以执行它们。

增加游泳池大小。