为什么在使用随机和线程池时输出顺序没有改变?
Why does the order of output not getting changed when using random and threadpool?
我正在尝试了解如何通过执行器使用线程池。
我正在尝试打印从 1 到 10 的 10
数字的阶乘结果(不一定按相同的顺序),以先完成的为准,然后让线程休眠 1-5 秒,这将被选为 运行domly .
这是我的可调用任务:
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 ;
}
}
这是我的主要内容 class:
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 不同,但再次 运行 多次将在此处产生相同的输出。
为什么输出没有运行domly?
提前致谢。
更新:
感谢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();
}
}
我相信这是因为您是在 while 循环 内 内声明迭代器,而不是在其外。这意味着您总是从可迭代对象中获取第一个元素,并检查它是否完成。如果不是,则再次循环,再次检查集合中的第一个元素。
它只是在迭代的当前头部完成后才从集合中选择下一个项目,因此您要按顺序删除项目。
让我们评估代码。首先,Future 存储在 HashSet 中。使用的 while 循环是迭代此 HashSet 。现在迭代器在这个循环中启动,迭代器 returns 第一个元素并检查它是否完成 (fi.isDone()) 如果它为 false 则循环结束并且过程继续(包括重新启动迭代器)这将一直持续到第一个元素已评估的时间。
到第一个结果被评估时,所有其他结果在不同线程中并行运行(因为有 10 个线程)也被评估。
当第一个结果完成时()然后它被打印出来并且也从 HashSet 中取出,因此下一次迭代的哈希集将少 1 个元素,因此 Iterator 将从第二个元素开始。这个过程(删除完成的元素并为剩余的 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));
我正在尝试了解如何通过执行器使用线程池。
我正在尝试打印从 1 到 10 的 10
数字的阶乘结果(不一定按相同的顺序),以先完成的为准,然后让线程休眠 1-5 秒,这将被选为 运行domly .
这是我的可调用任务:
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 ;
}
}
这是我的主要内容 class:
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 不同,但再次 运行 多次将在此处产生相同的输出。
为什么输出没有运行domly?
提前致谢。
更新:
感谢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();
}
}
我相信这是因为您是在 while 循环 内 内声明迭代器,而不是在其外。这意味着您总是从可迭代对象中获取第一个元素,并检查它是否完成。如果不是,则再次循环,再次检查集合中的第一个元素。
它只是在迭代的当前头部完成后才从集合中选择下一个项目,因此您要按顺序删除项目。
让我们评估代码。首先,Future 存储在 HashSet 中。使用的 while 循环是迭代此 HashSet 。现在迭代器在这个循环中启动,迭代器 returns 第一个元素并检查它是否完成 (fi.isDone()) 如果它为 false 则循环结束并且过程继续(包括重新启动迭代器)这将一直持续到第一个元素已评估的时间。 到第一个结果被评估时,所有其他结果在不同线程中并行运行(因为有 10 个线程)也被评估。
当第一个结果完成时()然后它被打印出来并且也从 HashSet 中取出,因此下一次迭代的哈希集将少 1 个元素,因此 Iterator 将从第二个元素开始。这个过程(删除完成的元素并为剩余的 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));