美文网首页
Java多线程,如何获取线程的返回值?

Java多线程,如何获取线程的返回值?

作者: 景知育德 | 来源:发表于2023-04-18 00:07 被阅读0次

    在 Java 中,我们常常开启多个线程来提高运行效率。但是有时候我们需要这些线程的返回值。应该如何获取线程的返回值呢?

    我现在有10万个整数,我需要开5个线程来找它们的最大值。每个线程处理2万个整数,然后返回这2万个整数的最大值。最终我们再找出整体的最大值。

    1. 使用线程安全的共享变量

    我们使用一个类似于 LinkedList 的共享变量来存放这5个线程各自找到的最大值。但是 LinkedList 是线程不安全的,所以可以换为 ConcurrentLinkedQueue 。

    import java.util.Random;
    import java.util.concurrent.ConcurrentLinkedQueue;
    
    public class MaxValueFinder {
    
        public static void main(String[] args) throws InterruptedException {
            int[] nums = generateNums(100000);
    
            ConcurrentLinkedQueue<Integer> resultQueue = new ConcurrentLinkedQueue<>();
    
            Thread[] threads = new Thread[5];
            for (int i = 0; i < threads.length; i++) {
                int startIndex = i * (nums.length / threads.length);
                int endIndex = (i + 1) * (nums.length / threads.length);
                threads[i] = new MaxValueThread(nums, startIndex, endIndex, resultQueue);
                threads[i].start();
            }
    
            for (Thread thread : threads) {
                thread.join();
            }
    
            int maxValue = resultQueue.poll();
            while (!resultQueue.isEmpty()) {
                int value = resultQueue.poll();
                if (value > maxValue) {
                    maxValue = value;
                }
            }
    
            System.out.println("Max value: " + maxValue);
        }
    
        private static int[] generateNums(int n) {
            int[] nums = new int[n];
            Random random = new Random();
            for (int i = 0; i < n; i++) {
                nums[i] = random.nextInt();
            }
            return nums;
        }
    
        static class MaxValueThread extends Thread {
            private int[] nums;
            private int startIndex;
            private int endIndex;
            private ConcurrentLinkedQueue<Integer> resultQueue;
    
            MaxValueThread(int[] nums, int startIndex, int endIndex, ConcurrentLinkedQueue<Integer> resultQueue) {
                this.nums = nums;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
                this.resultQueue = resultQueue;
            }
    
            @Override
            public void run() {
                int maxValue = nums[startIndex];
                for (int i = startIndex + 1; i < endIndex; i++) {
                    if (nums[i] > maxValue) {
                        maxValue = nums[i];
                    }
                }
                resultQueue.add(maxValue);
            }
        }
    }
    
    

    在这个示例中,我们创建了一个ConcurrentLinkedQueue来存储线程的计算结果。在每个线程的run方法中,线程会计算它被分配的一部分数组元素的最大值,并将结果添加到ConcurrentLinkedQueue中。在主线程中,我们从ConcurrentLinkedQueue中取出所有结果,找出最大值并输出。

    需要注意的是,ConcurrentLinkedQueue 虽然是线程安全的,但是并不能保证它的顺序,因此在处理结果时需要考虑顺序的问题。在这个示例中,我们只需要找出最大值,因此顺序不影响结果。如果需要按照顺序处理结果,可以考虑使用其他的线程安全集合。

    2. 使用Future+Callable

    import java.util.Random;
    import java.util.concurrent.*;
    
    public class MaxFinder {
        private static final int THREAD_COUNT = 5;
        private static final int ARRAY_SIZE = 100000;
        private static final int SUB_ARRAY_SIZE = ARRAY_SIZE / THREAD_COUNT;
        private static final int MAX_VALUE = 1000000;
    
        public static void main(String[] args) {
            int[] arr = generateRandomArray(ARRAY_SIZE);
    
            ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
            Future<Integer>[] futures = new Future[THREAD_COUNT];
    
            for (int i = 0; i < THREAD_COUNT; i++) {
                int startIndex = i * SUB_ARRAY_SIZE;
                int endIndex = (i + 1) * SUB_ARRAY_SIZE;
                futures[i] = executorService.submit(new MaxFinderTask(arr, startIndex, endIndex));
            }
    
            int max = Integer.MIN_VALUE;
            for (int i = 0; i < THREAD_COUNT; i++) {
                try {
                    int result = futures[i].get();
                    if (result > max) {
                        max = result;
                    }
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
    
            System.out.println("Max value: " + max);
    
            executorService.shutdown();
        }
    
        private static int[] generateRandomArray(int size) {
            int[] arr = new int[size];
            Random random = new Random();
            for (int i = 0; i < size; i++) {
                arr[i] = random.nextInt(MAX_VALUE);
            }
            return arr;
        }
    
        private static class MaxFinderTask implements Callable<Integer> {
            private final int[] arr;
            private final int startIndex;
            private final int endIndex;
    
            public MaxFinderTask(int[] arr, int startIndex, int endIndex) {
                this.arr = arr;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
            }
    
            @Override
            public Integer call() throws Exception {
                int max = Integer.MIN_VALUE;
                for (int i = startIndex; i < endIndex; i++) {
                    if (arr[i] > max) {
                        max = arr[i];
                    }
                }
                return max;
            }
        }
    }
    

    这个程序中,我们使用ExecutorService创建了一个线程池,然后使用Future来获取每个线程的结果。在主线程中,我们使用Future.get()方法来等待每个线程的结果,并使用它们来找到整个数组的最大值。注意,在这个例子中,我们使用Callable接口来创建每个线程的任务,并在任务的call()方法中返回结果。

    3. 使用Stream

    Stream(流)有点类似于 Golang 的管道,非常方便。

    Java 8引入了Stream API,可以对集合和数组等数据源进行流式操作,其中包括并行处理数据源的能力。下面是一个使用Stream来实现任务的示例代码:

    int[] nums = ...; // 10万个整数
    int parallelism = 5; // 并行度
    
    int max = Arrays.stream(nums)
                    .parallel()
                    .unordered()
                    .mapToInt(Integer::intValue)
                    .limit((long) Math.ceil(nums.length / (double) parallelism))
                    .max()
                    .getAsInt();
    
    

    这个示例代码首先将整数数组转换为流,然后使用parallel()方法启用并行流处理,使用unordered()方法告诉Stream不必保证元素顺序,使用mapToInt(Integer::intValue)方法将流中的元素转换为整数类型,使用limit()方法限制每个线程需要处理的元素个数,最后使用max()方法找到流中的最大值并返回。

    这个示例代码使用了Java 8的lambda表达式和方法引用,可以让代码更加简洁和易读。

    相关文章

      网友评论

          本文标题:Java多线程,如何获取线程的返回值?

          本文链接:https://www.haomeiwen.com/subject/aohhjdtx.html