多线程并发执行任务,取结果归集:Future、FutureTask、CompletionService、CompletableFuture

Future

(1)cancle

(2)get

(3)isCancle

(4)isDone

示例:

使用线程池提交Callable接口任务,返回Future接口,添加进李斯特,最后遍历FutureList且内部使用while轮询,并发获取结果

package thread.future;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 
 * @ClassName: FutureDemo
 * @Description: Future多线程并发任务结果归集
 * @author denny.zhang
 * @date 2016年11月4日 下午1:50:32
 *
 */
public class FutureDemo{

    public static void main(String[] args)  {
        Long start = System.currentTimeMillis();
        //开启多线程
        ExecutorService exs = Executors.newFixedThreadPool(10);
        try {
            //结果集
            List<Integer> list = new ArrayList<Integer>();
            List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
            //1.高速提交10个任务,每个任务返回一个Future入list
            for(int i=0;i<10;i++){
                futureList.add(exs.submit(new CallableTask(i+1)));
            }
            Long getResultStart = System.currentTimeMillis();
            System.out.println("结果归集开始时间="+new Date());
            //2.结果归集,遍历futureList,高速轮询(模拟实现了并发)获取future状态成功完成后获取结果,退出当前循环
            for (Future<Integer> future : futureList) {
                while (true) {//CPU高速轮询:每个future都并发轮循,判断完成状态然后获取结果,这一行,是本实现方案的精髓所在。即有10个future在高速轮询,完成一个future的获取结果,就关闭一个轮询
                    if (future.isDone()&& !future.isCancelled()) {//获取future成功完成状态,如果想要限制每个任务的超时时间,取消本行的状态判断+future.get(1000*1, TimeUnit.MILLISECONDS)+catch超时异常使用即可。
                        Integer i = future.get();//获取结果
                        System.out.println("任务i="+i+"获取完成!"+new Date());
                        list.add(i);
                        break;//当前future获取结果完毕,跳出while
                    } else {
                        Thread.sleep(1);//每次轮询休息1毫秒(CPU纳秒级),避免CPU高速轮循耗空CPU---》新手别忘记这个
                    }
                }
            }
            System.out.println("list="+list);
            System.out.println("总耗时="+(System.currentTimeMillis()-start)+",取结果归集耗时="+(System.currentTimeMillis()-getResultStart));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            exs.shutdown();
        }
    }
    static class CallableTask implements Callable<Integer>{
        Integer i;
        
        public CallableTask(Integer i) {
            super();
            this.i=i;
        }

        @Override
        public Integer call() throws Exception {
            if(i==1){
                Thread.sleep(3000);//任务1耗时3秒
            }else if(i==5){
                Thread.sleep(5000);//任务5耗时5秒
            }else{
                Thread.sleep(1000);//其它任务耗时1秒
            }
            System.out.println("task线程:"+Thread.currentThread().getName()+"任务i="+i+",完成!");  
            return i;
        }
    }
}

FutureTask

1.Runnable接口,可开启单个线程执行。

2.Future<v>接口,可接受Callable接口的返回值,futureTask.get阻塞获取结果。

/**
 * 
 * @ClassName:FutureTaskDemo
 * @Description:FutureTask弥补了Future必须用线程池提交返回Future的缺陷,实现功能如下:
 * 1.Runnable接口,可开启线程执行。
 * 2.Future<v>接口,可接受Callable接口的返回值,futureTask.get()阻塞获取结果。
 * 这两个步骤:一个开启线程执行任务,一个阻塞等待执行结果,分离这两步骤,可在这两步中间穿插别的相关业务逻辑。
 * @author diandian.zhang
 * @date 2017年6月16日上午10:36:05
 */
public class FutureTaskContorlDemo {
    
    public static void main(String[] args)  {
        try {
            System.out.println("=====例如一个统计公司总部和分部的总利润是否达标100万==========");
            //利润
            Integer count = 0;
            //1.定义一个futureTask,假设去远程http获取各个分公司业绩.
            FutureTask<Integer> futureTask = new FutureTask<Integer>(new CallableTask());
            Thread futureTaskThread =  new Thread(futureTask);
            futureTaskThread.start();
            System.out.println("futureTaskThread start!"+new Date());
            
            //2.主线程先做点别的事
            System.out.println("主线程查询总部公司利润开始时间:"+new Date());
            Thread.sleep(5000);
            count+=10;//北京集团总部利润。
            System.out.println("主线程查询总部公司利润结果时间:"+new Date());
            
            //总部已达标100万利润,就不再继续执行获取分公司业绩任务了
            if(count>=100){
                System.out.println("总部公司利润达标,取消futureTask!"+new Date());
                futureTask.cancel(true);//不需要再去获取结果,那么直接取消即可
            }else{
                System.out.println("总部公司利润未达标,进入阻塞查询分公司利润!"+new Date());
                //3总部未达标.阻塞获取,各个分公司结果
                Integer i = futureTask.get();//真正执行CallableTask
                System.out.println("i="+i+"获取到结果!"+new Date()+new Date());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 
     * @ClassName:CallableTask
     * @Description:一个十分耗时的任务
     * @author diandian.zhang
     * @date 2017年6月16日上午10:39:04
     */
    static class CallableTask implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("CallableTask-call,查询分公司利润,执行开始!"+new Date());
            Thread.sleep(10000);
            System.out.println("CallableTask-call,查询分公司利润,执行完毕!"+new Date());
            return 10;
        }
    }
package thread.future;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

/**
 * 
 * @ClassName:FutureTaskDemo
 * @Description:FutureTask实现多线程并发执行任务并取结果归集
 * @author diandian.zhang
 * @date 2017年6月16日上午10:36:05
 */
public class FutureTaskDemo {
    
    public static void main(String[] args)  {
        Long start = System.currentTimeMillis();
        //开启多线程
        ExecutorService exs = Executors.newFixedThreadPool(5);
        try {
            //结果集
            List<Integer> list = new ArrayList<Integer>();
            List<FutureTask<Integer>> futureList = new ArrayList<FutureTask<Integer>>();
            //启动线程池,10个任务固定线程数为5
            for(int i=0;i<10;i++){
                 FutureTask<Integer> futureTask = new FutureTask<Integer>(new CallableTask(i+1));
                //提交任务,添加返回
                exs.submit(futureTask);//Runnable特性
                futureList.add(futureTask);//Future特性
            }
            Long getResultStart = System.currentTimeMillis();
            System.out.println("结果归集开始时间="+new Date());
            //结果归集
            for (FutureTask<Integer> future : futureList) {
                while (true) {
                    if (future.isDone()&& !future.isCancelled()) {
                        Integer i = future.get();//Future特性
                        System.out.println("i="+i+"获取到结果!"+new Date());
                        list.add(i);
                        break;
                    }else {
                        Thread.sleep(1);//避免CPU高速轮循,可以休息一下。
                    }
                }
            }
            System.out.println("list="+list);
            System.out.println("总耗时="+(System.currentTimeMillis()-start)+",取结果归集耗时="+(System.currentTimeMillis()-getResultStart));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            exs.shutdown();
        }
        
    }

    static class CallableTask implements Callable<Integer>{
        Integer i;
        
        public CallableTask(Integer i) {
            super();
            this.i=i;
        }

        @Override
        public Integer call() throws Exception {
            if(i==1){
                Thread.sleep(3000);//任务1耗时3秒
            }else if(i==5){
                Thread.sleep(5000);//任务5耗时5秒
            }else{
                Thread.sleep(1000);//其它任务耗时1秒
            }
            System.out.println("线程:["+Thread.currentThread().getName()+"]任务i="+i+",完成!"+new Date());  
            return i;

        }
        
    }

}

CompletionService

原因:内部通过阻塞队列+FutureTask,实现了任务先完成可优先获取到,即结果完成后顺序排序。

package thread.future;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 
 * @ClassName: CompletionServiceDemo
 * @Description: CompletionService多线程并发任务结果归集
 * @author denny.zhang
 * @date 2016年11月4日 下午1:50:32
 *
 */
public class CompletionServiceDemo{

    public static void main(String[] args)  {
        Long start = System.currentTimeMillis();
        //开启3个线程
        ExecutorService exs = Executors.newFixedThreadPool(5);
        try {
            int taskCount = 10;
            //结果集
            List<Integer> list = new ArrayList<Integer>();
            //1.定义CompletionService
            CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(exs);  
            List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
            //2.添加任务
            for(int i=0;i<taskCount;i++){
                futureList.add(completionService.submit(new Task(i+1)));
            }
            //==================结果归集===================
            //方法1:future是提交时返回的,遍历queue则按照任务提交顺序,获取结果
//            for (Future<Integer> future : futureList) {
//                System.out.println("====================");
//                Integer result = future.get();//线程在这里阻塞等待该任务执行完毕,按照
//                System.out.println("任务result="+result+"获取到结果!"+new Date());
//                list.add(result);
//            }

//            //方法2.使用内部阻塞队列的take()
            for(int i=0;i<taskCount;i++){
                Integer result = completionService.take().get();//采用completionService.take(),内部维护阻塞队列,任务先完成的先获取到
                System.out.println("任务i=="+result+"完成!"+new Date());
                list.add(result);
            }
            System.out.println("list="+list);
            System.out.println("总耗时="+(System.currentTimeMillis()-start));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            exs.shutdown();//关闭线程池
        }
        
    }

    static class Task implements Callable<Integer>{
        Integer i;
        
        public Task(Integer i) {
            super();
            this.i=i;
        }

        @Override
        public Integer call() throws Exception {
            if(i==5){
                Thread.sleep(5000);
            }else{
                Thread.sleep(1000);
            }
            System.out.println("线程:"+Thread.currentThread().getName()+"任务i="+i+",执行完成!");  
            return i;
        }
        
    }
}

CompletableFuture

JDK1.8才新加入的实现类,实现Future、CompletionStage两个接口。

package thread.future;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.google.common.collect.Lists;

/**
 * 
 * @ClassName:CompletableFutureDemo
 * @Description:多线程并发任务,取结果归集
 * @author diandian.zhang
 * @date 2017年6月14日下午12:44:01
 */
public class CompletableFutureDemo {
    public static void main(String[] args) {
        Long start = System.currentTimeMillis();
        //结果集
        List<String> list = new ArrayList<String>();
        List<String> list2 = new ArrayList<String>();
        //定长10线程池
        ExecutorService exs = Executors.newFixedThreadPool(10);
        //List<CompletableFuture<String>> futureList = new ArrayList<>();
        List<Integer> taskList = Lists.newArrayList(2,1,3,4,5,6,7,8,9,10);
        try {
            //方式一:循环创建CompletableFuture list,调用sequence()组装返回一个有返回值的CompletableFuture,返回结果get()获取
//            for(int i=0;i<taskList.size();i++){
//                final int j=i+1;
//                CompletableFuture<String> future = CompletableFuture.supplyAsync(()->calc(j), exs)//异步执行
//                        .thenApply(e->Integer.toString(e))//Integer转换字符串    thenAccept只接受不返回不影响结果
                        .whenComplete((v, e) -> {//如需获取任务完成先手顺序,此处代码即可
                            System.out.println("任务"+v+"完成!result="+v+",异常 e="+e+","+new Date());
                            list2.add(v);
                        })
//                        ;
//                futureList.add(future);
//            }
//            //流式获取结果
//            list = sequence(futureList).get();//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]此处不理解为什么是这样的顺序?谁知道求告知
            
            //方式二:全流式处理转换成CompletableFuture[]+组装成一个无返回值CompletableFuture,join等待执行完毕。返回结果whenComplete获取
            @SuppressWarnings("rawtypes")
            CompletableFuture[] cfs = taskList.stream().map(object-> CompletableFuture.supplyAsync(()->calc(object), exs)
                    .thenApply(h->Integer.toString(h))
                    .whenComplete((v, e) -> {//如需获取任务完成先手顺序,此处代码即可
                        System.out.println("任务"+v+"完成!result="+v+",异常 e="+e+","+new Date());
                        list2.add(v);
                    }))
                    .toArray(CompletableFuture[]::new);
            CompletableFuture.allOf(cfs).join();//封装后无返回值,必须自己whenComplete()获取
            System.out.println("list2="+list2+"list="+list+",耗时="+(System.currentTimeMillis()-start));
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            exs.shutdown();
        }
    }
    
    public static Integer calc(Integer i){
        try {
            if(i==1){
                Thread.sleep(3000);//任务1耗时3秒
            }else if(i==5){
                Thread.sleep(5000);//任务5耗时5秒
            }else{
                Thread.sleep(1000);//其它任务耗时1秒
            }
            System.out.println("task线程:"+Thread.currentThread().getName()+"任务i="+i+",完成!+"+new Date());  
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return i;
    }
    
    /**
     * 
     * @Description 组合多个CompletableFuture为一个CompletableFuture,所有子任务全部完成,组合后的任务才会完成。带返回值,可直接get.
     * @param futures List
     * @return
     * @author diandian.zhang
     * @date 2017年6月19日下午3:01:09
     * @since JDK1.8
     */
    public static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {
        //1.构造一个空CompletableFuture,子任务数为入参任务list size
        CompletableFuture<Void> allDoneFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
        //2.流式(每个子任务join操作后转换为list)往空CompletableFuture中添加结果
        return allDoneFuture.thenApply(v -> futures.stream().map(CompletableFuture::join).collect(Collectors.<T>toList()));
    }
   
    /**
     * 
     * @Description Stream流式类型futures转换成一个CompletableFuture,所有子任务全部完成,组合后的任务才会完成。带返回值,可直接get.
     * @param futures Stream
     * @return
     * @author diandian.zhang
     * @date 2017年6月19日下午6:23:40
     * @since JDK1.8
     */
    public static <T> CompletableFuture<List<T>> sequence(Stream<CompletableFuture<T>> futures) {
        List<CompletableFuture<T>> futureList = futures.filter(f -> f != null).collect(Collectors.toList());
        return sequence(futureList);
    }
}

 

最后欢迎大家访问我的个人网站:1024s​​​​​​​

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值