【问题标题】:Why does the order of output not getting changed when using random and threadpool?为什么使用随机和线程池时输出顺序没有改变?
【发布时间】:2019-11-30 04:38:20
【问题描述】:

我正在尝试通过 Executors 了解如何使用线程池。 我正在尝试打印从 1 到 10 的 10 数字的阶乘结果(不一定以相同的顺序),以先完成者为准,然后让线程休眠 1-5 秒,这将随机选择。

这是我的可调用任务

 class FactorialCalculator implements Callable{
    @Override
    public Integer call() throws Exception {
        int i= 1, temp = num;
        while (temp > 1){
            i = i*temp;
            temp--;
        }
        int x = ThreadLocalRandom.current().nextInt(1, 6);
        Thread.sleep(x * 1000);
        return i ;
    }

}

这是我的主要课程:

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService e = Executors.newFixedThreadPool(10);
        Set <Future<Integer>> set= new HashSet<Future<Integer>>();
        int totalSum = 0;
        for (int i = 1; i <= 10; i++) {
            set.add(e.submit(new FactorialCalculator(i)));
        }
        while(!set.isEmpty()) {
            Iterator<Future<Integer>> iter =  set.iterator();
            Future<Integer> fi = iter.next();
            if(fi.isDone()) {
                int temp = fi.get();
                System.out.println(temp);
                iter.remove();  
            }   
        }
   }

我在 Eclipse 上运行了这个程序 10 次,每次输出都一样。

然后我通过命令提示符编译它,然后在那里运行它。输出与 eclipse 不同,但再次运行多次将在此处产生相同的输出。

为什么输出不是随机出现的?

提前致谢。

更新:

感谢 Ben 指出问题:

这是我所做的更改:

Iterator<Future<Integer>> iter =  list.iterator();
        while(!list.isEmpty()) {
            Future<Integer> fi = iter.next();
            if(fi.isDone()) {
                int temp = fi.get();
                System.out.println(temp);
                iter.remove();  
            }
            if(!list.isEmpty() && iter.hasNext() == false) {
                iter =  list.iterator();
            }
        }

【问题讨论】:

    标签: java random threadpool future executorservice


    【解决方案1】:

    让我们评估一下代码。首先,Future 存储在 HashSet 中。使用的 while 循环是迭代这个 HashSet 。现在迭代器在此循环内启动,迭代器返回第一个元素并检查是否已完成(fi.isDone()),如果它为假,则循环结束并继续处理(包括重新启动迭代器),这将一直持续到第一个时间元素已评估。 到第一个结果被评估时,所有其他结果在不同线程中并行运行(因为有 10 个线程)也被评估。

    当第一个结果是 done() 然后它被打印并从 HashSet 中取出,因此 Next while 迭代的 Hash 集将少 1 个元素,因此 Iterator 将从 2nd element 开始。这个过程(删除 done 元素并为剩余的 HasSet 初始化迭代器)将一直持续到 HasSet 为空(while 循环的条件)

    现在此代码强制按 HashSet 存储的顺序打印结果(如上所述)(HasSet 不保证任何顺序,但插入的相同元素(无论以何种顺序)将具有存储在 HasSet 中的相同顺序,并且从 1 到每次送10个相同的号码,每次按相同的顺序存储) 为了让 Ex Try below 代码理解它,Bothe 迭代将打印相同的顺序,即使它们以不同的顺序插入。

    Set<Integer> intSet = new HashSet<Integer>();
    
    for(int i = 11 ; i <= 20 ; i++){
      intSet.add(i);
    
    }
    
    for(Integer integer : intSet){
      System.out.println(integer);
    }
    
    System.out.println("+++++++++++++");
    
    intSet.clear();
    
    for(int i = 20 ; i >= 11 ; i--){
      intSet.add(i);
    
    }
    
    intSet.forEach(integer -> System.out.println(integer));
    

    【讨论】:

      【解决方案2】:

      我相信这是因为您将迭代器声明在 inside while 循环中,而不是在它之外。这意味着您总是从可迭代对象中获取第一个元素,并检查它是否已完成。如果不是,则再次循环,再次检查集合中的第一个元素。

      只有在迭代的当前头完成后才从集合中选择下一个项目,因此您正在按顺序删除项目。

      【讨论】:

      • 我不知道是谁否决了这个答案,它是正确的。 iterable 从第一项开始一次又一次地启动,直到它的isDone 为真。
      • 确保您再次覆盖所有 not isDone 元素不是正确的吗?
      • @VinayPrajapati OP 试图做的是打印第一个完成的未来,然后是第二个完成的未来,等等。所以循环逻辑是,当集合不为空时,你会通过它搜索完成的元素。如果有,您打印并删除它。你一次又一次地经历它,直到你完成。不幸的是,如果你一次又一次地检索迭代器没有第二个内部循环,你只会轮询第一个元素直到它完成。
      • @VinayPrajapati 我读了。如果逻辑如我描述的那样,打印将是随机的,因为完成线程的顺序是随机的。但是,循环是不正确的,因此它总是按照元素在迭代器中出现的顺序打印元素。
      • @Ben 实际上你是对的。根据您的提示,我进行了一些更改,现在它每次都随机打印输出。 +1
      猜你喜欢
      • 2014-02-21
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      • 1970-01-01
      • 2014-05-03
      • 2012-11-06
      相关资源
      最近更新 更多