【问题标题】:Why tasks in Threadpool are not executed following FIFO, Java为什么线程池中的任务没有按照 FIFO、Java 执行
【发布时间】:2017-06-28 10:12:54
【问题描述】:

我知道如果队列已满,新任务将由新创建的线程根据How to guarantee FIFO execution order in a ThreadPoolExecutor优先执行

但我有以下测试代码 sn-ps,其中 min core size = max core size。

public class ThreadPoolFifoTest {
    public static void main(String[] args) throws InterruptedException {
        Executor ex = Executors.newFixedThreadPool(10);
        final List<Integer> l = new LinkedList<Integer>();
        final ReentrantLock lock = new ReentrantLock(true);//fair lock
        for(int i=0;i<10000;i++){
            final int num = i ;
            ex.execute(new Runnable() {//FIFO submit 
                @Override
                public void run() {
                    //here since queue is FIFO, it is easy to consider that somebody should be take the task FIFO and let the thread to run this task
                    //so it easy to consider that this should be fifo to go to here. 
                    //But as a result , it is not.
                    lock.lock();
                    l.add(num);
                    lock.unlock();                 
                }
            });
        }

        Thread.sleep(1000);
        System.out.println(l);
        List<Integer> sortedList= new LinkedList<Integer>(l);
        Collections.sort(sortedList);
        System.out.println(sortedList);
        System.out.println(l.equals(sortedList));//not equals here

    }
}

输出:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 9, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
false

由于线程池下的队列是先进先出,任务应该是轮询先进先出并在线程中运行,所以由于我是按照顺序0.1.2.3.4.....999提交任务,我的l应该看起来像sorted,但是从输出来看,不是,这不是说执行顺序不是FIFO吗?为什么不?

如果我需要FIFO执行任务怎么办?

【问题讨论】:

  • 您尚未对l 进行排序,而是从l! 创建了一个新列表。你说的是什么执行顺序?
  • @CKing ,我的意思是,我从 0->999 提交任务,在我的 run() 方法中,我将数字放入 FIFO 列表,如果执行是 FIFO,我的列表应该是排序,但从输出来看,它不是。
  • 是的,我现在知道你的问题了。我之前看错了。请注意,添加 lock 并不能确保线程将按顺序运行。它只确保当一个线程正在写入时,另一个线程正在等待。
  • 你有十个线程。它们都将同时运行。这里没有 FIFO 行为。
  • 用户可以随意考虑,但线程并发执行。这就是他们的目的。你可以按你喜欢的任何顺序启动它们,你可以用队列来控制它,但这就是你对它的控制的结束。

标签: java multithreading threadpool


【解决方案1】:

问题是线程只按顺序取出消息,但独立运行(线程应该)如果你想在 FIFO 中执行,你应该要么

  • 使用单线程,因为无论如何您都无法并行运行任务。
  • 使用多线程,但按创建顺序(而不是执行顺序)收集结果。这就是 parallelStream 的作用。

例如

List<Result> results = IntStream.range(0, 10000).parallel()
                                .mapToObject(i -> func(i))
                                .collect(Collector.toList());

这将允许并发执行,但结果以原始顺序显示。

顺便说一句,当您对 LinkedList 进行排序时,它必须将其转换为数组,对其进行排序并将其复制回链表中。我建议使用可以就地排序的 ArrayList。

【讨论】:

  • 乍一看有点奇怪,但似乎一个线程已独立地从流中获取值并计算其组合操作,然后只将下一个值提供给下一个线程,我是否在思考正确的方向澄清一下?
  • @Prashant 每个线程都有自己的工作队列,但如果工作用完,也支持工作窃取。任务按顺序添加到队列中,但同时删除。
  • 说 T1 在队列中有 {0,1,2,3} 而 T2 有{4,5,6,7},假设如果 T2 完成对队列中值的操作集并且 T1 是仍在进行中,{3} 会被 T2 带走吗?应该始终还是只在 ForkJoinPool 或 WorkStealingPool 中?
  • @Prashant 是的,一个 ThreadExecutorPool 有一个跨线程共享的队列,当你有更少、更昂贵的任务时这会更简单,当你有更多、更小的任务时,WorkStealingPool 会更好。
猜你喜欢
  • 2019-10-08
  • 2016-06-24
  • 1970-01-01
  • 2012-03-19
  • 1970-01-01
  • 2013-07-22
  • 2018-02-04
  • 2022-01-10
  • 2017-02-16
相关资源
最近更新 更多