Callable和CompletionService的使用

前言:

1、实现功能大体与"Callable 和 FutureTask 的使用" 相似

2、此文主要用于介绍CompletionService实现的利弊,故请先了解FutureTask 相关知识

下面比较FutureTask 和 CompletionService 的差别:

代码如下:

public class MyCompletionService implements Callable<String> {

    private String userName;
    private long sleepTime;

    public MyCompletionService(String userName, long sleepTime) {
        this.userName = userName;
        this.sleepTime = sleepTime;
    }

    @Override
    public String call() throws Exception {
        Thread.sleep(sleepTime);
        return userName;
    }

    public static void main(String[] args) throws InterruptedException,ExecutionException {
        MyCompletionService service1 = new MyCompletionService("aaa",1800);
        MyCompletionService service2 = new MyCompletionService("bbb",1000);
        MyCompletionService service3 = new MyCompletionService("ccc",3000);
        MyCompletionService service4 = new MyCompletionService("ddd",2400);
        MyCompletionService service5 = new MyCompletionService("eee",3600);
        List<Callable> list = new ArrayList<Callable>();
        list.add(service1);
        list.add(service2);
        list.add(service3);
        list.add(service4);
        list.add(service5);
        ExecutorService executor = Executors.newFixedThreadPool(10);

        // CompletionService
        CompletionService<String> completionService = new ExecutorCompletionService(executor);
        System.out.println("startTime:"+System.currentTimeMillis());
        for (int i = 0;i<5;i++){
            // 提交对象必须是callable类型
            completionService.submit(list.get(i));
        }
        for (int i = 0;i<5;i++){
            System.out.println("等待打印第"+(i+1)+"个返回值");
            System.out.println("userName:"+completionService.take().get()+"-当前时间:"+System.currentTimeMillis());
        }
        System.out.println("endTime:"+System.currentTimeMillis());

        // futureTask
        FutureTask<String> task1 = new FutureTask<>(service1);
        FutureTask<String> task2 = new FutureTask<>(service2);
        FutureTask<String> task3 = new FutureTask<>(service3);
        FutureTask<String> task4 = new FutureTask<>(service4);
        FutureTask<String> task5 = new FutureTask<>(service5);
        List<FutureTask> ftList = new ArrayList<>();
        ftList.add(task1);
        ftList.add(task2);
        ftList.add(task3);
        ftList.add(task4);
        ftList.add(task5);
        System.out.println("startTime:"+System.currentTimeMillis());
        for (int i = 0;i < 5;i++){
            executor.execute(ftList.get(i));
        }
        for (int i = 0;i < 5;i++) {
            System.out.println("等待打印第"+(i+1)+"个返回值");
            System.out.println("userName:"+ftList.get(i).get()+"---"+System.currentTimeMillis());
        }
        System.out.println("endTime:"+System.currentTimeMillis());
    }
}

 

上方的为CompletionService执行结果,下方为FutrueTask执行结果

其实从业务执行时间上看,消耗时间实质上差不多,但区别是:

1,FutureTask一定是按照调用get()方法的顺序执行的,但调用get()方法是会阻塞主线程,如果两个子线程第一个执行速度慢于第二个线程,那么输出的一定是同时输出。

2,CompletionService的则是按照线程先执行完的顺序输出的,改善了FutureTask的get()方法阻塞!。

下面执行一个业务系统的demo,其他类的代码在"Callable 和 FutureTask 的使用"一文中。

public Map<String,Object> sendMailAndMessage2(Map<String, Object> params){
    MailCallable mailCallable = new MailCallable(params);
    MessageCallable messageCallable = new MessageCallable(params);
    List<Callable> list = new ArrayList<>();
    list.add(mailCallable);
    list.add(messageCallable);
    // 创建线程池
    ExecutorService executor = Executors.newFixedThreadPool(5);
    // 将线程池作为参数传入completionService中
    CompletionService completionService = new ExecutorCompletionService(executor);
    Map<String,Object> map = new HashMap<String, Object>();
    try {
        for (int i = 0; i < list.size(); i++) {
            completionService.submit(list.get(i));
        }
        for (int i = 0; i < list.size(); i++) {
            map.putAll((Map<String, Object>)completionService.take().get());
        }
    }catch (Exception e){
        e.printStackTrace();
    }
    return map;
}

执行结果:

 

必要的五步:

//1、创建线程池(这里需要考虑线程池是单独给以下逻辑使用,还是全局使用的问题,单独使用放在方法中,全局使用放在外部)
ThreadPoolExecutor executor = DefaultThreadPoolFactory.initThreadPool(5, 10);
//2、创建异步执行器(VO只是一个实体类,没有做任何处理)
CompletionService<VO> completionService = new ExecutorCompletionService(executor);
//3、任务提交给异步执行器(这里submit的类对象必须实现Callable接口,此处用匿名内部类的方式new CallAble(){}})
    completionService.submit(() -> {
        //业务代码

    });
//4、获取执行结果(submit了几个,获取几次)
for (int i = 0; i < VOList.size(); i++) {
    VO vo = completionService.take().get();
    if (null != vo){
        dataList.add(vo);
    }
}
//5、关闭线程池
executor.shutdown();

实际中应用例子(浙江省xxx项目中源代码)

// 创建线程池,有自己已经封装好的代码类
ThreadPoolExecutor executor = DefaultThreadPoolFactory.initThreadPool(5, 10);
// 创建异步执行器,泛型里写要操作的实体类
CompletionService<VO> completionService = new ExecutorCompletionService(executor);
// list中的vo都并发执行操作
for (VO vo : baseVOList) {
    completionService.submit(() -> {
        //业务代码
        
    });
}
// 获取每个线程执行的值
for (int i = 0; i < baseVOList.size(); i++) {
    SentimentProcessBaseVO vo = completionService.take().get();
    if (null != vo){
        dataList.add(vo);
    }
}
// 关闭线程池
executor.shutdown();

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值