java.util.concurrent学习(五-2) ExecutorCompletionService扩展有序的SortedExecutorCompletionService

该博客介绍了如何通过扩展ExecutorCompletionService来保持异步任务结果的有序性。作者创建了一个SortedExecutorCompletionService类,通过维护一个映射关系,在提交任务时记录每个任务的排序信息。当获取结果时,根据映射关系重建有序结果列表,解决了原有ExecutorCompletionService可能导致的结果无序问题。源码展示和测试用例进一步解释了实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ExecutorCompletionService学习中我们知道,ExecutorCompletionService通过装饰器模式提供了获取已完成的线程结果功能,这大大提高了我们的线程池结果聚合效率。但是这种方式有一种弊端,当我们将已经排好序的结果进行异步提交的时候,获取到的结果是无序的,我们只有通过重新排序或者与之前的排序结果进行对比才能重新得到我们想要的结果,这在开发中无疑提高了代码复杂度,同时也会造成不必要的bug和代码重复。那么我们想一下,能不能有一种方式帮助我们同时使用ExecutorCompletionService的功能,又不会造成结果乱序呢?为此,我对ExecutorCompletionService做了进一步的扩展。大概原理如下:
在这里插入图片描述
1 在提交任务时,我们可以获取到线程的future引用,此时通过map建立future和排序的映射关系,作为后续结果排序的依据。
2 在poll出结果后,重新拿到future对象,此时通过排序映射关系获取原始的排序下角标,然后构建一个结果集数组,将结果放入对应的位置。
3 当所有的结果都处理完以后,我们就得到了一个有序的结果数组,但是由于异步执行的不确定性,有些线程可能由于某种原因没有执行完成,导致数组的部分位置是没有元素的。因此,我们需要将数组重新过滤一遍,组装成新的有序列表返回。

下面是源码展示:

package com.tangjianghua.juc.threadpool.extend;

import java.util.*;
import java.util.concurrent.*;

/**
 * @auth tangjianghua
 * @date 2021/6/15
 */
public class SortedExecutorCompletionService<V> extends ExecutorCompletionService {

    /**
     * 当前下角标
     */
    private int index;

    /**
     * 位置映射
     * future -> index
     */
    private Map<Future<V>, Integer> sortedMap = new HashMap<>();

    /**
     * 位置映射
     * v -> index
     */
    private Map<V, Integer> vSortedMap = new HashMap<>();

    /**
     * 是否已经排序
     */
    private boolean sorted;

    /**
     * 结果集
     * 如果sorted=true,则该结果集为已排序的结果集
     */
    private volatile List<V> result = null;


    /**
     * 结果集锁
     */
    private Object lock = new Object();

    public boolean isSorted() {
        return sorted;
    }

    public SortedExecutorCompletionService(Executor executor) {
        super(executor);
    }

    public SortedExecutorCompletionService(Executor executor, BlockingQueue completionQueue) {
        super(executor, completionQueue);
    }

    @Override
    public Future submit(Callable task) {
        Future future = super.submit(task);
        sortedMap.put(future, index++);
        return future;
    }

    /**
     * 获取排好序的结果
     *
     * @param timeOut
     * @param timeUnit
     * @return 已排序返回 List<V>
     * 未排序但已获取结果
     */
    public List<V> getAllSortedResult(Long timeOut, TimeUnit timeUnit) {
        if (result == null) {
            synchronized (lock) {
                if (result == null) {
                    Object[] arrayList = new Object[index];
                    for (int i = 0; i < index; i++) {
                        try {
                            Future<V> future = super.poll(timeOut, timeUnit);
                            if (future != null) {
                                V v = future.get();
                                arrayList[sortedMap.get(future)] = v;
                                vSortedMap.put(v, sortedMap.get(future));
                            }
                        } catch (InterruptedException | ExecutionException e) {
                            e.printStackTrace();
                        }
                    }
                    result = new ArrayList<>();
                    Arrays.stream(arrayList)
                            .filter(Objects::nonNull)
                            .forEach(o -> result.add((V) o));
                    this.sorted = true;
                }
            }
        }
        //未排序 但已获取过结果
        //将已获取过结果的任务重新排序
        if (!sorted) {
            synchronized (lock) {
                if (!sorted) {
                    Object[] arrayList = new Object[vSortedMap.size()];
                    vSortedMap.entrySet().stream()
                            .forEach(vIntegerEntry -> arrayList[vIntegerEntry.getValue()] = vIntegerEntry.getKey());
                    result = new ArrayList<>();
                    Arrays.stream(arrayList)
                            .filter(Objects::nonNull)
                            .forEach(o -> result.add((V) o));
                }
                sorted = true;
            }
        }
        return result;
    }

    /**
     * 获取未排序的结果
     *
     * @param timeOut
     * @param timeUnit
     * @return
     */
    public List<V> getAllResult(Long timeOut, TimeUnit timeUnit) {
        if (result == null) {
            synchronized (lock) {
                if (result == null) {
                    result = new ArrayList<>(index);
                    for (int i = 0; i < index; i++) {
                        try {
                            Future<V> future = super.poll(timeOut, timeUnit);
                            if (future != null) {
                                V v = future.get();
                                result.add(v);
                                vSortedMap.put(v, sortedMap.get(future));
                            }
                        } catch (InterruptedException | ExecutionException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return result;
    }
}

使用方法

package com.tangjianghua.juc.threadpool.extend;

import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;

import java.util.*;
import java.util.concurrent.*;

/**
 * @auth tangjianghua
 * @date 2021/6/15
 */
public class SortedExecutorCompletionServiceTest{

    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));
        SortedExecutorCompletionService sortedExecutorCompletionService = new SortedExecutorCompletionService<>(threadPoolExecutor);

        for (int i = 0; i < 100; i++) {
            final int j=i;
            sortedExecutorCompletionService.submit(() -> {return j;});
        }
//        List list = sortedExecutorCompletionService.getAllResult(10L, TimeUnit.SECONDS);
//        list.stream().forEach(System.out::println);
        List allSortedResult = sortedExecutorCompletionService.getAllSortedResult(10L, TimeUnit.SECONDS);
        allSortedResult.stream().forEach(System.out::println);
        threadPoolExecutor.shutdown();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值