Future ,FutrueTask,ForkJoinPool 等异步多线程执行工具案例

  • 1、Future 异步执行获取执行结果

我们知道通过Thread+Runnable可异步执行某项操作,但是如何异步执行后,并获取执行结果?
Thread和Runnable并没有提供获取执行结果的操作。
Runnable 是对任务的封装
在JDK1.5提供了Future和Callable 接口的定义,
Future是对异步执行线程并获取结果的线程封装,提供获取执行结果或取消任务操作。
Callable<T> 接口是完成异步执行任务的封装,T call()方法执行业务逻辑。
要想异步执行任务,并获取结果,就必须同时实现Runnable和Future 2个接口,JDK提供了FutureTask<T> implements RunnableFuture<V> 类型。
获取异步执行并获取结果逻辑:
1、自定义业务实现 Callable<T> 接口,并实现call()
2、创建FutureTask<T> 实例,传递Callable实例
FutureTask<Integer> futureTask=new FutureTask<>(callable)
3、通过线程启动任务
new Thead(futureTask).start()

4、如果想获取结果,堵塞(内部是通过堵塞或轮询实现)
T t=futureTask.get();
5、如果想取消任务,是通过信号标识取消的,需要在call()中实现,通过信号量取消逻辑
futureTask.cancel(true);

  • 2、Future 异步执行,获取执行结果案例
public class FutureTest {
    //业务类(执行方法获取返回值)
    private static class BussInfo implements Callable<Integer> {
        private Integer count;
        public BussInfo(Integer i){
            count=i;
        }
        //具体业务是对值加100
        @Override
        public Integer call() throws Exception {
            //判断任务是否取消
            while(count<50000) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("==================任务已取消================");
                    break;
                } else {
                    count++;
                }
            }
            return count;
        }
    }

    public static void main(String[] args) {
        //线程异步执行,获取结果
        BussInfo bussInfo=new BussInfo(10);
        FutureTask<Integer> futureTask=new FutureTask<>(bussInfo);
        new Thread(futureTask).start();

        //模拟任务执行,有时可取消任务
        Random rd=new Random();
        int i = rd.nextInt(10);
        try {
            //线程会堵塞
            Integer integer=0;
            if(i>5) {
                integer = futureTask.get();
            }else{
                //取消任务,使用的是信号,需要在call()写信号判断
                futureTask.cancel(true);
            }
            System.out.println("integer = " + integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"-main is ended");
    }
}

3、采用Future实现异步的缺点,采用ForkJoin 思想实现的ForkJoinPool完成任务拆分和合并案例
1、获取结果需要堵塞get()或轮询isDone(),未实现异步执行完后采用通知或回调的方法
2、控制多个Future 结果之间的依赖性,如部分完成后进行合并结果等操作

ForkJoin 案例,将大任务分成逻辑相同的小任务,各个任务之间没有依赖。分而治之思想
 * 1、ForkJoinPool 执行ForkJoin的线程池,提供多线程异步执行,提供线程Fork和Join操作
 * 2、RecursiveAction 不需要返回结果的子任务,RecursiveTask<V> 需要返回结果
 * 3、定义业务类继承RecursiveAction或RecursiveTask<V>,在compute()方法中完成任务的Fork和Join操作

  • 3.1、RecursiveAction 无返回值案例
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName ForkJoinTest
 * @Description ForkJoin 案例,将大任务分成逻辑相同的小任务,各个任务之间没有依赖。分而治之思想
 * 1、ForkJoinPool 执行ForkJoin的线程池,提供多线程异步执行,提供线程Fork和Join操作
 * 2、RecursiveAction 不需要返回结果的子任务,RecursiveTask<V> 需要返回结果
 * 3、定义业务类继承RecursiveAction或RecursiveTask<V>,在compute()方法中完成任务的Fork和Join操作
 * 案例:多任务把oldLst数组中的值复制到newLst中。
 **/
public class ForkJoinActionTest {
    private static int count=10000;
    private static List<Integer> oldLst=new ArrayList<>(count);
    private static List<Integer> newLst=new ArrayList<>(count);
    //初始化就集合值
    static {
        for(int i=count;i>0;i--){
            oldLst.add(i);
            //数组需要提前初始化,否则修改不了值
            newLst.add(0);
        }
    }

    public static void main(String[] args) {
        System.out.println("oldLst:"+oldLst.toString());
        System.out.println("newLst:"+newLst.toString());
        RecursiveActionTest action=new RecursiveActionTest(0,count,oldLst,newLst);
        ForkJoinPool pool=ForkJoinPool.commonPool();
        pool.submit(action);
        try {
            pool.awaitTermination(3000, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        pool.shutdown();
        System.out.println("main is ended");
        System.out.println("oldLst:"+oldLst.toString());
        System.out.println("newLst:"+newLst.toString());
    }
    /*
    * 不需要返回值的Fork案例;
    * 多任务把一个数组中数据复制到另一个数组中*/
    private static class RecursiveActionTest extends RecursiveAction{
        //子任务阈值大小
        private static Integer preSize=100;
        private int start;
        private int end;
        private List<Integer> oldLst;
        private List<Integer> newLst;
        public RecursiveActionTest(int start,int end,List<Integer> oldLst,List<Integer> newLst){
            this.start=start;
            this.end=end;
            this.oldLst=oldLst;
            this.newLst=newLst;
        }
        @Override
        protected void compute() {
            if((end-start)<preSize){
                System.out.println(Thread.currentThread().getName()+"-start:"+start+",end:"+end);
                for(int i=start;i<end;i++){
                    newLst.set(i, oldLst.get(i));
                }
                //System.out.println(Thread.currentThread().getName()+"-------执行子任务----"+start+"-this:"+this.hashCode());
            }else{
                //分成子任务
                int middle=(start+end)/2;
                RecursiveActionTest action1=new RecursiveActionTest(start,middle,oldLst,newLst);
                RecursiveActionTest action2=new RecursiveActionTest(middle,end,oldLst,newLst);
                //执行所有子任务
                RecursiveActionTest.invokeAll(action1,action2);
                //System.out.println(Thread.currentThread().getName()+"========分配任务====="+middle+"-this:"+this.hashCode());
            }
        }
    }
}
  • 3.2、RecursiveTask<V> 有返回值案例
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * @ClassName ForkJoinTaskTest
 * @Description 采用多任务,对一个数组中的值进行求和运算
 **/
public class ForkJoinTaskTest {
    private static List<Integer> lst=new ArrayList<>();

    static {
        //初始化数组中的值
        for(int i=0;i<10000;i++){
            lst.add(i);
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ForkJoinPool pool=ForkJoinPool.commonPool();//JDK1.8提供的共用池,默认线程数是CPU核数
        ForkJoinTask<Integer> submit = pool.submit(new RecursiveTaskTest(0, lst.size(), lst));
        //Fork&Join后获取总结果,堵塞
        Integer count = submit.get();
        System.out.println("count = " + count);
    }
    //fork&join 操作,运算数组中所有数的和
    private static class RecursiveTaskTest extends RecursiveTask<Integer>{
        private int preSize=100;
        private int start;
        private int end;
        private List<Integer> list;
        public RecursiveTaskTest(int start,int end,List<Integer> list){
            this.start=start;
            this.end=end;
            this.list=list;
        }
        @Override
        protected Integer compute() {
            Integer sum=0;
            if(end-start<preSize){
                for(int i=start;i<end;i++){
                    sum=sum+lst.get(i);
                }
            }else{
                int middle=(end+start)/2;
                RecursiveTaskTest action1=new RecursiveTaskTest(start,middle,list);
                RecursiveTaskTest action2=new RecursiveTaskTest(middle,end,list);
                //执行所有任务
                RecursiveTaskTest.invokeAll(action1,action2);
                //执行Join操作(堵塞)
                sum=action1.join()+action2.join();
            }
            return sum;
        }
    }
}

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值