并发框架类及其功能(2)

Future和Callable

这里写图片描述

public class FutureTest {
    static class Task implements Callable{
        @Override
        public Object call() throws Exception {
            Thread.sleep(3000);
            return "<html><h1>Hello World</h1></html>";
        }
    }

    public static void main(String...args) throws ExecutionException, InterruptedException {
        Callable task = new Task();
        ExecutorService service = Executors.newFixedThreadPool(3);
        Future<String> future = service.submit(task);
        service.shutdown();

        System.out.println(System.currentTimeMillis());
        System.out.println(future.get());
        System.out.println(System.currentTimeMillis());
    }
}

/*
1505622184281
<html><h1>Hello World</h1></html>
1505622187281
*/
Future的缺点:Future接口调用get()方法是堵塞的,也就是如果任务未完成则会堵塞并等待完成。并且有多个任务时,当调用最耗时的任务的get()时,会等待过久的时间。但此时可能别的任务已经完成了,但我们不能做任何事情。

CompletionService

以异步的方式,一边生产新的任务,一边处理已完成任务的结果。最先完成的任务,会被最先处理,所以能解决Future的问题。

这里写图片描述

public class CompletionServiceTest {
    static class MyCallable implements Callable<String>{
        private String username;
        private long sleepValue;

        public MyCallable(String username, long sleepValue) {
            this.username = username;
            this.sleepValue = sleepValue;
        }

        @Override
        public String call() throws Exception {
            System.out.println(username);
            Thread.sleep(sleepValue);
            return "return "+username;
        }
    }

    public static void main(String...args){
        try {
            MyCallable c1 = new MyCallable("username1",5000);
            MyCallable c2 = new MyCallable("username2",4000);
            MyCallable c3 = new MyCallable("username3",3000);
            MyCallable c4 = new MyCallable("username4",2000);
            MyCallable c5 = new MyCallable("username5",1000);

            List<Callable> list = new ArrayList<>();
            list.add(c1);
            list.add(c2);
            list.add(c3);
            list.add(c4);
            list.add(c5);

            ThreadPoolExecutor executor
                    = new ThreadPoolExecutor(5,10,5, TimeUnit.SECONDS,
                    new LinkedBlockingDeque<>());
            CompletionService csRef = new ExecutorCompletionService(executor);

            for (int i = 0;i < 5;i++){
                csRef.submit(list.get(i));
            }

            executor.shutdown();

            for (int i = 0;i < 5;i++){
                System.out.println("等待打印"+(i+1)+"个返回值");
                System.out.println(csRef.take().get());
            }


        }catch (Exception r){}
    }
}

/*
username1
username4
username3
username2
username5
等待打印1个返回值
return username5
等待打印2个返回值
return username4
等待打印3个返回值
return username3
等待打印4个返回值
return username2
等待打印5个返回值
return username1
*/
take()会取得最先完成任务的Future对象,如果没有则堵塞等待。
poll()会获取并移除下一个已完成任务的Future,如果不存在已完成的任务,则返回null,不会阻塞。

ExecutorService

这里写图片描述

invokeAny()会堵塞,并获取在一大堆Callable中取得最先完成的任务,然后返回。但是其他任务还是会继续运行,不会停止。但是会将线程interrupt标志设置为true,线程可以选择处理来停止任务。
invokeAll()会堵塞,并等待全部任务都完成,并返回所有任务的执行结果。

ScheduledExecutorService

将定时任务和线程池功能结合使用。

这里写图片描述


Fork-Join

这里写图片描述
这里写图片描述

ForkJoinPool提供了一个任务池,但执行任务的是ForkJoinTask类,ForkJoinTask是个抽象类,有三个抽象子类:CountedCompleter, RecursionAction, RecursiveTask。

这里写图片描述

三个抽象子类实现了除compute()的别的方法,所以,我们的任务就是继承并重写这个方法。

执行任务

public class ForkJoinTest {
    static class MyRecursiveAction extends RecursiveAction{
        @Override
        protected void compute() {
            System.out.println("Computer");
        }
    }

    public static void main(String...args) throws InterruptedException {
        ForkJoinPool pool = new ForkJoinPool();
        pool.submit(new MyRecursiveAction());
        Thread.sleep(20);
    }
}

分解任务

public class ForkJoinTest {
    static class MyRecursiveAction extends RecursiveAction{
        private int beginValue;
        private int endValue;

        public MyRecursiveAction(int beginValue, int endValue) {
            this.beginValue = beginValue;
            this.endValue = endValue;
        }

        @Override
        protected void compute() {
            //System.out.println("---"+Thread.currentThread()+"---");
            if (endValue - beginValue > 2){
                int middle = (beginValue + endValue)/2;
                MyRecursiveAction left = new MyRecursiveAction(beginValue,middle);
                MyRecursiveAction right = new MyRecursiveAction(middle+1,endValue);
                this.invokeAll(left,right);
            }else{
                System.out.println("打印组合为:"+beginValue+"-"+endValue);
            }
        }
    }

    public static void main(String...args) throws InterruptedException {
        ForkJoinPool pool = new ForkJoinPool();
        pool.submit(new MyRecursiveAction(1,100));
        pool.awaitQuiescence(5, TimeUnit.SECONDS);
    }
}

/*
打印组合为:76-77
打印组合为:78-79
打印组合为:1-2
打印组合为:64-66
打印组合为:51-52
打印组合为:58-60
打印组合为:61-63
打印组合为:14-16
打印组合为:17-19
......
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值