并发编程(四)CompletionService

并发编程(四)CompletionService

1.1 什么是CompletionService

简单的并行任务我们直接使用线程池各自提交任务就可以了,需要获取结果的或者线程之间有依赖关系的我们可以使用Future,当然对于复杂的关系例如线程之间的串行,并行,聚合等关系,java也提供了ComplableFuture来简化我们对线程的操作。

CompletionService java提供的一种批量处理线程的类CompletionService。

1.2 CompletionService基本原理和使用

其实就是内部维护了一个阻塞队列,阻塞队列里边存储了各个线程执行完之后的Future对象。

CompletionService的实现类有ExecutorCompletionService两个构造方法 :

/**
* 如果不传如阻塞队列默认使用的是一个无界的阻塞队列LinkedBlockingQueue
*/
public ExecutorCompletionService(Executor executor) {
        if (executor == null)
            throw new NullPointerException();
        this.executor = executor;
        this.aes = (executor instanceof AbstractExecutorService) ?
            (AbstractExecutorService) executor : null;
        this.completionQueue = new LinkedBlockingQueue<Future<V>>();
    }

 public ExecutorCompletionService(Executor executor,
                                     BlockingQueue<Future<V>> completionQueue) {
        if (executor == null || completionQueue == null)
            throw new NullPointerException();
        this.executor = executor;
        this.aes = (executor instanceof AbstractExecutorService) ?
            (AbstractExecutorService) executor : null;
        this.completionQueue = completionQueue;
    }

CompletionService执行批量任务

/**
 * 任务的批量处理
 * @author:
 * @Date: 2019-06-26 18:28
 * @Copyright: 2019 www.lenovo.com Inc. All rights reserved.
 */
public class CompletionServiceDemo {

    public static void main(String[] args)throws Exception {
        //两个构造方法 不传队列使用默认的无界队列 LinkedBlockingQueue
        CompletionService service1 = new 				   ExecutorCompletionService(TestThreadPool.getInstance());

        service1.submit(()->{
            TimeUnit.SECONDS.sleep(3);
            return "task1";
        });

        service1.submit(()->{
            TimeUnit.SECONDS.sleep(4);
            return "task2";
        });

        service1.submit(()->{
            TimeUnit.SECONDS.sleep(1);
            return "task3";
        });

        for(int i=0;i<3;i++){
            Future take = service1.take();
            System.out.println(take.get());
        }

    }
}

CompletionService的重要方法

Future<V> submit(Callable<V> task);
Future<V> submit(Runnable task, V result);
/**
*从阻塞队列中获取一个Future 并且删除,如果队列为空阻塞
*/
Future<V> take() 
  throws InterruptedException;
/**
*从阻塞队列中获取一个Future 并且删除,如果队列为空返回null
*/
Future<V> poll();
/**
*从阻塞队列中获取一个Future 并且删除,支持超时机制,超过超时时间还没有获取到结果,返回null
*/
Future<V> poll(long timeout, TimeUnit unit) 
  throws InterruptedException;

1.4 实现Dubbo的Forking Cluster

首先要明白Dubbo的ForkingCluster是什么 ,其实就是并行的调用多个查询服务,只要有一个成功返回数据,这个服务就可以返回了。

利用CompletionService可以非常简单的实现这个功能。

/**
 * @author:
 * @Date: 2019-06-26 19:26
 * @Copyright: 2019 www.lenovo.com Inc. All rights reserved.
 */
public class DubboForkingClusterSimulation {

    public static void main(String[] args)throws Exception {
        ExecutorCompletionService<String> batchService = new ExecutorCompletionService(TestThreadPool.getInstance());
        List<Future> tasks = new ArrayList<>(3);
        tasks.add(batchService.submit(()->f1()));
        tasks.add(batchService.submit(()->f2()));
        tasks.add(batchService.submit(()->f3()));

        for(int i=0;i<3;i++){
             String result = batchService.take().get();
             System.out.println(result);
             if(! StringUtils.isEmpty(result)){
                 break;
             }
        }
        tasks.forEach(f->{
            f.cancel(true);
        });

    }

    private static String f1()throws Exception{
        TimeUnit.SECONDS.sleep(6);
        return "f1 invoke success";
    }

    private static String f2()throws Exception{
        TimeUnit.SECONDS.sleep(3);
        return "f2 invoke success";
    }

    private static String f3()throws  Exception{
        TimeUnit.SECONDS.sleep(8);
        return "f3 invoke success";
    }
}

上边的代码中有一个服务成功返回之后,就停止其他的服务,进行返回。

猜你喜欢

转载自blog.csdn.net/weixin_39034379/article/details/93792673