有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java线程池的工作方式不可预测

我有一个简单的任务: 这里有一个数组列表,我需要使用threadpool在所有数组中找到除以10的数字

这是我的密码

导入java。util。名单

可运行的实现:

public class MyRunnable implements Runnable {
    private List<Integer> numbers;
    private int[] arrayToFind;

    public MyRunnable(List<Integer> numbers, int[] arrayToFind) {
        this.numbers = numbers;
        this.arrayToFind = arrayToFind;
    }

    private boolean isNumber(int n) {
        return n % 10 == 0;
    }

    @Override
    public void run() {
        for (int i = 0; i < arrayToFind.length; i++) {
            if (isNumber(arrayToFind[i]))
                numbers.add(arrayToFind[i]);
        }
    }
}

主要类别:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

    public static void main(String... args) throws InterruptedException{
        int[] arr1 = new int[] {10};
        int[] arr2 = new int[] {400};
        int[] arr3 = new int[] {20};
        int[] arr4 = new int[] {40};
        List<int[]> list = new ArrayList<int[]>();
        list.add(arr1);
        list.add(arr2);
        list.add(arr3);
        list.add(arr4);

        List<Integer> result = new ArrayList<Integer>();

        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int[] array : list) {
            executorService.execute(new MyRunnable(result, array));
        }
        executorService.shutdown();

        System.out.println(result);
    }
}

问题是,输出有时是正确的,因为它应该是{10,20,40,400},但有时是{},有时是{40,20},等等

你怎么解释


共 (3) 个答案

  1. # 1 楼答案

    默认情况下,在列表中插入are not synchronized,因此不是线程安全的。如果希望实现线程安全(这样就不会丢失数据),那么将实例包装在Collections.synchronizedList

    List<Integer> result = Collections.synchronizedList(new ArrayList<Integer>());
    

    现在,您的结果将全部显示(当然,仍然是不确定的顺序)

  2. # 2 楼答案

    在ExecutorService的API中。shutdown,它说:“这个方法不会等待之前提交的任务完成执行。使用awaitTermination可以完成这项任务。”

    试着用它。我打赌这会解决你的问题

  3. # 3 楼答案

    似乎有时候Executor服务会关闭,直到一些或您的MyRunnable。跑步结束了。一般来说,我们的服务很好。execute+Runnable允许您在对结果不感兴趣的情况下并行执行“一些工作”。如果需要等待所有结果计算完毕,请使用ExecutorService。invokeAll+Callable。例如,见:

    http://tutorials.jenkov.com/java-util-concurrent/executorservice.html

    最后,将计算结果存储在线程安全的集合中:

    public static class MyCallable implements Callable<Boolean> {
        private Set<Integer> numbers;
        private int[] arrayToFind;
    
        public MyCallable(Set<Integer> numbers, int[] arrayToFind) {
            this.numbers = numbers;
            this.arrayToFind = arrayToFind;
        }
    
        private boolean isNumber(int n) {
            return n % 10 == 0;
        }
    
        @Override
        public Boolean call() {
            for (int i = 0; i < arrayToFind.length; i++) {
                if (isNumber(arrayToFind[i]))
                    numbers.add(arrayToFind[i]);
            }
            return true;
        }
    }
    
    
    public static void main(String... args) throws InterruptedException{
        int[] arr1 = new int[] {10};
        int[] arr2 = new int[] {400};
        int[] arr3 = new int[] {20};
        int[] arr4 = new int[] {40};
        List<int[]> list = new ArrayList<>();
        list.add(arr1);
        list.add(arr2);
        list.add(arr3);
        list.add(arr4);
    
        Set<Integer> result = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
        List<MyCallable> myCallables = new ArrayList<>();
        for (int[] array : list) {
            myCallables.add(new MyCallable(result, array));
        }
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.invokeAll(myCallables);
        executorService.shutdown();
        System.out.println(result);
    }