当前位置: 首页 > 知识库问答 >
问题:

为什么使用随机和线程池时输出的顺序不会改变?

戚学
2023-03-14

我试图通过执行器学习使用线程池。我试图打印的阶乘结果的10数字从1到10(不一定在相同的顺序),无论先完成,然后让线程Hibernate1-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();
            }
        }

共有2个答案

晏弘雅
2023-03-14

让我们评估一下代码。首先,未来存储在HashSet中。所使用的而循环用于迭代此HashSet。现在迭代器在这个循环中启动,迭代器返回第一个元素,如果它为假,那么循环结束,过程继续(包括重新启动迭代器),这将持续到第一个元素的时间已评估。当计算第一个结果时,所有其他结果在不同的线程中并行运行(因为有10个线程)也会被计算。

当第一个结果完成(),然后它被打印出来,也从HashSet中取出,所以下一个迭代的哈希集将减少1个元素,因此迭代器将从第2个元素开始。这个过程(删除完成的元素并为剩余的HasSet初始化迭代器)将持续到HasSet为空(而循环的条件)

现在,此代码强制按HashSet存储的顺序打印结果(如上所述)(HasSet不保证任何顺序,但插入的相同html" target="_blank">元素(无论以何种顺序)将在HasSet中存储相同的顺序,并且由于每次输入1到10个相同的数字,因此每次都将以相同的顺序存储)为了让下面的代码理解它,两次迭代都将打印相同的顺序,即使它们以不同的顺序插入。

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));
阴元青
2023-03-14

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

它只在iterable的当前标题完成后才从集合中选择下一个项目,因此您将按顺序删除项目。

 类似资料:
  • 问题内容: 因此,我对Node.js的工作方式有所了解:它具有一个侦听器线程,该线程接收事件,然后将其委托给工作池。工作线程一旦完成工作,便会通知侦听器,然后侦听器将响应返回给调用者。 我的问题是:如果我在Node.js中建立一个HTTP服务器,并在我的一个路由路径事件(例如“ / test / sleep”)中调用sleep,那么整个系统就会停顿下来。甚至是单个侦听器线程。但是我的理解是这段代码

  • 为什么改变求和顺序会返回不同的结果? = Java和JavaScript都返回相同的结果。 我知道,由于浮点数在二进制中的表示方式,一些有理数(如1/3-0.333333...)不能精确表示。 为什么简单地改变元素的顺序会影响结果?

  • 本文向大家介绍为什么要用线程池? 相关面试题,主要包含被问及为什么要用线程池? 时的应答技巧和注意事项,需要的朋友参考一下 池化技术相比大家已经屡见不鲜了,线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。** 线程池提供了一种限制和管理资源(包括执行一个任务)。 每个线程池还维护一些基本统计信息,例如已完成任务的数

  • 问题内容: 为什么更改总和顺序会返回不同的结果? = = 双方的Java和JavaScript的返回相同的结果。 我知道,由于以二进制表示浮点数的方式,某些有理数( 例如1/3-0.333333 … )无法精确表示。 为什么简单地更改元素的顺序会影响结果? 问题答案: 也许这个问题很愚蠢,但是为什么仅仅改变元素的顺序会影响结果呢? 它将根据值的大小更改四舍五入的点。作为示例 _样的_事情,我们所看

  • 参考Java的Fork/Join vs ExecutorService-何时使用哪个?,传统的线程池通常用于处理许多独立请求;用于处理连贯/递归任务,其中一个任务可能会产生另一个子任务并稍后加入。 那么,为什么Java-8的默认使用而不是传统的执行器? 在许多情况下,我们在或之后使用,然后提交一个函数式接口作为参数。从我的角度来看,这些任务是独立的,不是吗?

  • 这是我现在实际做的事情,因为我的部分代码使用超线程会得到更糟糕的结果,所以我将线程数降低到物理核心数(仅针对这部分代码)。如果我做了相反的事情(4个线程,然后8个,然后4个)呢? 线程池必须在每次更改线程数时重新创建吗?如果不是,添加或删除线程是否会导致任何显著的开销? 线程池的开销是多少,即每个线程有多少部分的工作流到池中?