CachedThreadPool满足但不启动第二个线程的任何原因?

时间:2014-02-20 15:04:30

标签: java multithreading threadpool

想象一下需要时间的软件,它会接收一堆文本文件(每个100多MB),处理它们并放入数据库。我正在尝试通过使用更多内核来优化它(对于这台机器来说恰好是8,这是一个带有超线程的四核i7)。

考虑以下代码:

    ExecutorService es = Executors.newCachedThreadPool(
            new ThreadFactory() {
                private final AtomicInteger threadNumber = new AtomicInteger(1);
                private final String namePrefix = "awesome-thread-";

                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
                    if (t.isDaemon()) 
                        t.setDaemon(false);
                    return t;
        }
    });

    while((e = upp.getNextEntry()) != null){

        // start time-consuming process in a separate thread to speed up
        Future<Set<Fragment>> fut = es.submit(new FragmentTask(e.getSomeProperty()));       

        /* do other stuff #sequentially# with entry e
         * it may or may not take as long as previous step
         * depending on e 
         */

        Set<Fragment> set = fut.get(); 
        for(Fragment frag : set){
            // do stuff with frag
        }                       
    }

此处FragmentTask包含一个递归算法,执行时间从几千到几千毫秒,具体取决于e

我最初将线程池实现为FixedThreadPool但是当我直观地检查线程的运行方式时(通过JVisualVM),我意识到线程通常是空闲的。我想我会尝试CachedThreadPool作为替代方案,但看起来因为池是一个单独的线程,在整个while循环中几乎以100%运行。在此过程中,不会随时创建池的辅助线程,其他核心也非常闲置。真正有趣的是,执行while循环中其余部分的“主”工作线程实际上一直在“等待”。

我觉得这有点奇怪,因为我希望至少有两个线程能够以更高的效率运行,一个运行FragmentTask,另一个运行其余的东西在while循环上,向上 - 到fut.get()

关于幕后可能发生什么的任何想法?代码“太顺序”是否可以使用线程池?

2 个答案:

答案 0 :(得分:1)

你正在以错误的方式使用期货来并行执行。您需要先提交所有任务并保存他们的未来,然后再打电话。调用get等待任务完成。

您现在正在做的是提交在自己的线程上执行的任务,然后主线程等待任务完成。冲洗并重复。

你说你期待两个主题。这确实是你拥有的 - 主线程和一个执行程序线程。

答案 1 :(得分:1)

问题不在于线程池实现。您尝试一次获得一个Future,因此您的程序基本上是单线程的。

您应该做的是创建Collection的{​​{1}}并使用:

Callable

然后循环遍历final List<Future<Set<Fragment>>> results = executor.invokeAll(yourCollectionOfCallables); 。当一个任务完成时,线程池将尽力启动具有新任务的线程;更重要的是,当你遍历所有列表时,你可以保证所有任务都已完成(成功或不成功)。