JAVA多线程(八)——Callable,FutureTask以及CompletableFuture简介

Callale

对于Callable大家应该都很熟悉,它与Runnable属于线程的顶级接口,不过它与Runnale不同的是,它支持线程返回执行结果,下面是它的使用方法:

package com.example.demo.thread;

import java.util.concurrent.*;

/**
 * @author : sun
 * create at:  2020/4/29  22:20
 * @description: 创建线程的方法4--实现Callable接口
 */
public class MyThread04 implements Callable {
    @Override
    public Integer call() throws Exception {
        System.out.println( Thread.currentThread().getName() +" 启动了");
        TimeUnit.SECONDS.sleep(10);
        return 1;
    }

    public static void main(String[] args) throws Exception {
        /**
         * 通过FutreTask包装启动
         */
        MyThread04 myThread04 = new MyThread04();
        FutureTask task = new FutureTask(myThread04);
        Thread thread = new Thread(task,"线程一");
        thread.start();

        System.out.println(task.get());
        /**
         * 通过线程池启动
         */
        ExecutorService service = Executors.newFixedThreadPool(1);
        Future<Integer> result = service.submit(myThread04);
        System.out.println(result.get());
        service.shutdown();
    }
}

从这段代码中,我可以看到Callable一般与FutureTask一起使用。同时在线程池中,我们可以通过submit方法来执行Callable线程来获得一个返回值。

FutureTask

简介

在介绍FutureTask之前我们要先了解一下Future接口,它提供了几个方法,其中最主要的get方法就是我们FutureTask的一个重点方法,他们的关系图如下:
在这里插入图片描述
从这个关系图中我们可以看出,FutureTask实现的RunnableFuture接口继承了Runnable,所以FutureTask也可以看作一个线程类,它可以自己启动一个线程,也可以将它交给线程池执行。
接下来我们来分析它的重要方法:

get方法

在这里插入图片描述
get方法是它最常用的方法,它提供了无参和有参的get方法,从参数可以看到,有参的get方法其实是入参了一个时间和这个时间单位,联系get方法会造成阻塞,我们可以想象到,他应该是规定了我get方法阻塞的时间,如果超过这个时间我就不会一直阻塞在那。
它的执行流程时:判断state状态(需要注意的是这个值是volatile修饰的,保证了线程之间的可见性),如果状态是未执行或者执行中调用awaitDone方法等待任务结束;如果执行完成,调用report方法返回执行结果。report方法就是看线程时正常结束还是异常结束,如果正常结束,返回执行结果;如果是CANCELLED状态、INTERRUPTING状态(中断中)或者INTERRUPTED状态(中断),则抛出异常。
state状态介绍

状态值状态说明介绍
0NEW刚刚创建,初始状态
1COMPLETING表示一个新的任务,初始状态
2NORMAL任务正常结束
3EXCEPTIONAL任务异常而结束
4CANCELLED任务被取消
5INTERRUPTING中断中,任务调用cancel(true)
6INTERRUPTED这是INTERRUPTING的最终状态,中断状态

awaitDone方法

在这里插入图片描述
这段代码可以看出,方法内部维护了一个state状态,根据这个状态值判断操作。它里面有个循环,直到state达到一个最终态或者等待时间超时或者线程中断才会跳出循环,即拿到结果。

cancel方法

在这里插入图片描述
同样,cancel取消任务,首先也要对state状态进行判断,如果线程还没启动,那就直接返回false,如果可以中断线程,那就中断线程。

上面的状态说明表格中,最后的CANCELLED与INTERRUPTING状态都是调用cancel(true)出现的

看了这两个方法,是不是很有印象,state+自旋,所以FutureTask也是基于ASQ模板来实现的。关于AQS的介绍可以查看我另一篇文章AQS——个人学习笔记

run方法

在这里插入图片描述
在它的核心run方法中,首先会先判断state状态,如果任务不是创建(NEW)状态或者通过自旋无法替换成当前线程,直接返回;接着就是通过callable的call方法来获得线程执行结果。(callable对象是通过FutureTask的构造函数获得的);任务结束后需要将工作线程设置为null。

FutureTask使用样例

package com.example.demo.thread.future;

import java.util.concurrent.*;

/**
 * @author: sunzhinan
 * @create: 2020-07-21 00:01
 * @description: FutureTask测试类
 */
public class TestFutureTask {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
         * 方法一
         */
        FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
        //这里需要注意的是,将futuretask交由Thread其本意是创建一个线程来执行子任务
        //当然你也可以直接调用futuretask的run方法,那么执行这个任务的线程就是主线程
        Thread thread = new Thread(futureTask,"线程1");
        thread.start();

        System.out.println("开始调用get方法");
        System.out.println(futureTask.get());
        System.out.println("调用get方法结束");


        /*
         * 方法二
         */
        System.out.println("----通过线程池----");
        FutureTask<Integer> task = new FutureTask<>(new MyCallable());
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.submit(task);
        //注意这里是task来get
        System.out.println("future,我的执行结果为:" + task.get());
        executor.shutdown();

    }
}

实际场景应用

目前还没找到,如果以后有发现会进行补充。

CompletableFuture

简介

CompletableFutrue是JDK8后新加入的一个类,在介绍FutureTask的时候就说过,FutureTask取结果的时候会造成阻塞,虽然它提供了isDone方法来循环判断任务是否完成,但是它会消耗系统性能,所以我们不调用get方法就不知道任务什么时候能完成,可以取出结果。
而CompletableFuture就解决了上诉阻塞这个缺点,在任务完成时,需要用到结果时,无需等待,可以将处理结果交给另一个处理线程来处理。

使用示例

package com.example.demo.thread.threadpool;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @author: sunzhinan
 * @create: 2020-05-24 15:45
 * @description: CompletableFuture
 */
public class TestCompletableFuture {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //通过看supplyAsync方法还有一个两个参数的supplyAsync(Supplier<U> supplier,Executor executor)
        //然后通过源码可以看出,其实supplyAsync会将参数一任务交给它默认的ForkJoinPool线程池执行。
        //同时你也可以通过第二个参数指定一个线程池
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行任务");
            return 20;
        });

        //CompletableFuture也有get方法和FutureTask一样都会造成阻塞
        //System.out.println(future.get());

        //thenAccept没有返回值,也就是说拿到CompletableFuture执行结果后再进行处理,不需要返回什么
        System.out.println("------thenAccept start------");
        future.thenAccept((i)->{
            System.out.println("------------");
            System.out.println(i);
        });
        System.out.println("------thenAccept end------");
        
        //thenApply有返回值,也就是说拿到CompletableFuture执行结果后再进行处理,可以再获得结果再返回
        System.out.println("------thenApply start------");
        CompletableFuture<String> cFuture = future.thenApply((i)->{
            System.out.println("------------");
            System.out.println(i);
            return "222";
        });
        System.out.println("------thenApply end------");

        //上面的thenAccept和thenApply方法都有对应的Async异步操作,也即是thenAcceptAsync和thenApplyAsync
        //同样,他们也是将任务交给线程池执行,你也可以指定线程池

        //这里一定要加上,因为主线程不能结束,如果主线程(理解为初始化CompletableFuture的线程)结束,
        //则CompletableFuture使用的线程池会立刻关闭
        System.out.println("让主线程等待");
        TimeUnit.SECONDS.sleep(10);
        System.out.println("cFuture : " + cFuture.get());
        System.out.println("------OK------");
    }
}

常见方法说明

通过阅读源码,发现CompletableFuture还有很多方法,这里我整理了一下:

方法参数说明
runAsyncrunAsync(Runnable runnable),runAsync(Runnable runnable,Executor executor)runAsync方法不支持返回值
supplyAsyncsupplyAsync(Supplier< U > supplier),supplyAsync(Supplier< U > supplier, Executor executor)supplyAsync可以支持返回值
thenApplythenApply( Function<? super T,? extends U> fn)将任务串行,下一个任务需要等待上一个执行任务的线程执行完毕
thenApplyAsyncthenApplyAsync(Function<? super T,? extends U> fn),thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)等上一个任务执行完毕后可以使用线程池中的空闲的线程执行此任务
thenAcceptthenAccept(Consumer<? super T> action)用于获得任务处理的结果
thenAcceptAsyncthenAcceptAsync(Consumer<? super T> action),thenAcceptAsync(Consumer<? super T> action, Executor executor)使用空闲线程来获得任务处理的结果
thenRunthenRun(Runnable action)与thenAccept的区别是不关心结果,它同样有Async异步的方法
whenCompletewhenComplete(BiConsumer<? super T, ? super Throwable> action)执行之前任务的线程继续执行 whenComplete 的任务
whenCompleteAsyncwhenCompleteAsync( BiConsumer<? super T, ? super Throwable> action),whenCompleteAsync( BiConsumer<? super T, ? super Throwable> action, Executor executor)使用其他线程执行whenCompleteAsync的任务
handlehandle( BiFunction<? super T, Throwable, ? extends U> fn)与whenComplete有返回和无返回的区别
handleAsynchandleAsync(BiFunction<? super T, Throwable, ? extends U> fn),handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)与whenCompleteAsync有返回和无返回的区别
anyOfanyOf(CompletableFuture<?>… cfs)CompletableFuture任务哪个先执行完毕获得哪个结果
thenCombinethenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)将两个CompletableFuture任务结果处理返回
thenCombineAsyncthenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)等与thenCombine不同的是会使用线程池中的空闲线程处理事件
thenAcceptBoththenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action)与thenCombine区别是没有返回值
thenAcceptBothAsyncthenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action)与thenCombineAsync区别是没有返回值

这里我先列举上述的这些方法,除此之外还有:thenCompose,runAfterBoth,runAfterEither ,
acceptEither ,applyToEither 等方法。这些方法其实大多数差不多,有兴趣的同学可以去编写代码试
试,下面就是我写的一些方法示例,可做参考。

thenApply与thenApplyAsync

package com.example.demo.thread.completableFuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author: sunzhinan
 * @create: 2020-05-24 16:49
 * @description: CompletableFuture
 */
public class TestCompletableFuture01 {

    public static void main(String[] args) throws InterruptedException {

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{

            System.out.println(" future1 开始执行, 当前线程:" + Thread.currentThread().getName());
            System.out.println("开始获得商品");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得商品结束");
            return "aaa";
        });

        CompletableFuture<Double> future2 = future1.thenApplyAsync((name)->{

            System.out.println(" future2 开始执行 , 当前线程:" + Thread.currentThread().getName());
            System.out.println("商品是: " + name);
            System.out.println("开始获得价格");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得价格结束");
            return 2.5;
        });

        CompletableFuture<Integer> future3 = future2.thenApplyAsync((price)->{

            System.out.println(" future3 开始执行, 当前线程:" + Thread.currentThread().getName());
            System.out.println("3: 商品价格是: " + price);
            System.out.println("开始获得热度");
            try {
                TimeUnit.SECONDS.sleep(7);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得热度结束");
            return 22500;
        });

        CompletableFuture<String> future4 = future2.thenApplyAsync((price)->{

            System.out.println(" future4 开始执行, 当前线程:" + Thread.currentThread().getName());
            System.out.println("4: 商品价格是: " + price);
            System.out.println("开始获得评论");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得评论结束");
            return "OK";
        });

        CompletableFuture<Integer> future5 = future2.thenApply((price)->{

            System.out.println(" future5 开始执行, 当前线程:" + Thread.currentThread().getName());
            System.out.println("5: 商品价格是: " + price);
            System.out.println("开始获得销量");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得销量结束");
            return 500;
        });

        CompletableFuture<Integer> future6 = future5.thenApplyAsync((num)->{

            System.out.println(" future6 开始执行, 当前线程:" + Thread.currentThread().getName());
            System.out.println("6: 商品销量是: " + num);
            System.out.println("开始获得人气");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得人气结束");
            return 1000;
        });

        future3.thenAccept((result)-> System.out.println("result3 : " + result));

        future4.thenAccept((result)-> System.out.println("result4 : " + result));

        //如果使用thenAcceptAsync你可以发现比thenAccept多了一个线程
//        future5.thenAcceptAsync((result)-> System.out.println("result5 : " + result));
        future5.thenAccept((result)-> System.out.println("result6 : " + result));

        future6.thenAccept((result)-> System.out.println("result6 : " + result));
        //thenRun不关心结果
//        future6.thenRun(() -> System.out.println("result6 :"));

        System.out.println("让主线程等待");
        TimeUnit.SECONDS.sleep(30);
        System.out.println("------OK------");
    }
}

anyOf

package com.example.demo.thread.completableFuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author: sunzhinan
 * @create: 2020-05-24 17:06
 * @description: CompletableFuture 并行
 */
public class TestCompletableFuture02 {

    public static void main(String[] args) throws InterruptedException {

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{
            System.out.println("开始获得商品1");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得商品1结束");
            return "aaa";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{
            System.out.println("开始获得商品2");
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得商品2结束");
            return "bbb";
        });

        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(()->{
            System.out.println("开始获得商品3");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得商品3结束");
            return "bbb";
        });

        // 用anyOf合并
        CompletableFuture<Object> nameFuture = CompletableFuture.anyOf(future1, future2,future3);

        nameFuture.thenAccept((result) -> {
            System.out.println("------name------");
            System.out.println("name: " + result);
            System.out.println("------name------");
        });

        // 两个CompletableFuture执行异步查询:
        CompletableFuture<Double> dFuture1 = nameFuture.thenApplyAsync((price) -> {
            System.out.println("开始获得价格1");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得价格1结束");
            return 3.5;
        });
        CompletableFuture<Double> dFuture2 = nameFuture.thenApplyAsync((price) -> {
            System.out.println("开始获得价格2");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得价格2结束");
            return 2.6;
        });

        //合并
        CompletableFuture<Object> priceFuture = CompletableFuture.anyOf(dFuture1, dFuture2);

        priceFuture.thenAccept((result) -> {
            System.out.println("------price------");
            System.out.println("price: " + result);
            System.out.println("------price------");
        });

        System.out.println("让主线程等待");
        TimeUnit.SECONDS.sleep(15);
        System.out.println("------OK------");
    }
}

whenComplete与whenCompleteAsync

package com.example.demo.thread.completableFuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author: sunzhinan
 * @create: 2020-07-22 22:34
 * @description: whenComplete
 */
public class TestCompletableFuture03 {

    public static void main(String[] args) throws InterruptedException {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(()->{
            System.out.println("future1 开始执行,当前线程是: " + Thread.currentThread().getName());
            try {
                //处理
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("future1 执行结束");
            return 100;
        });

        //位置1--
        CompletableFuture<Integer> future2 = future1.whenComplete((a,throwable) ->{
            System.out.println(" future1 的执行结果是 :" + a);
            System.out.println("future2 开始执行,当前线程是: " + Thread.currentThread().getName());
            try {
                //处理
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("future2 执行结束");
        });
        //位置1--

        //位置2--
        CompletableFuture<Integer> future3 = future1.whenCompleteAsync((a,throwable) ->{
            System.out.println(" future1 的执行结果是 :" + a);
            System.out.println("future3 开始执行,当前线程是: " + Thread.currentThread().getName());
            try {
                //处理
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("future3 执行结束");
        });
        //位置2--

        CompletableFuture<Integer> future4 = future1.whenComplete((a,throwable) ->{
            System.out.println(" future1 的执行结果是 :" + a);
            System.out.println("future4 开始执行,当前线程是: " + Thread.currentThread().getName());
            try {
                //处理
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("future4 执行结束");
        });

        CompletableFuture<Integer> future5 = future1.whenComplete((a,throwable) ->{
            System.out.println(" future1 的执行结果是 :" + a);
            System.out.println("future5 开始执行,当前线程是: " + Thread.currentThread().getName());
            try {
                //处理
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("future5 执行结束");

        });

        future1.thenAccept((result)-> System.out.println("result1 : " + result));
        future2.thenAccept((result)-> System.out.println("result2 : " + result));
        future3.thenAccept((result)-> System.out.println("result3 : " + result));
        future4.thenAccept((result)-> System.out.println("result4 : " + result));
        future5.thenAccept((result)-> System.out.println("result5 : " + result));

        System.out.println("让主线程等待");
        TimeUnit.SECONDS.sleep(8);
        System.out.println("------OK------");

        /**
         * 结果:
         * future1 开始执行,当前线程是: ForkJoinPool.commonPool-worker-1
         * 让主线程等待
         * future1 执行结束
         * result1 : 100
         *  future1 的执行结果是 :100
         * future5 开始执行,当前线程是: ForkJoinPool.commonPool-worker-1
         * future5 执行结束
         * result5 : 100
         *  future1 的执行结果是 :100
         * future4 开始执行,当前线程是: ForkJoinPool.commonPool-worker-1
         * future4 执行结束
         * result4 : 100
         *  future1 的执行结果是 :100
         * future2 开始执行,当前线程是: ForkJoinPool.commonPool-worker-1
         *  future1 的执行结果是 :100
         * future3 开始执行,当前线程是: ForkJoinPool.commonPool-worker-2
         * future2 执行结束
         * future3 执行结束
         * result2 : 100
         * result3 : 100
         * ------OK------
         * 从上述结果可以看出,执行whenComplete任务的线程是之前执行future所使用的线程,
         * 同时后面的whenComplete会在之前的whenComplete先执行,
         * whenCompleteAsync会等所有whenComplete执行完毕再执行,这个whenCompleteAsync的位置没有关系
         * 既:位置1和位置2的代码对换,其执行结果没有变化
         * 参数:throwable 异常
         */
    }
}

thenCombine与thenAcceptBoth

package com.example.demo.thread.completableFuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;

/**
 * @author: sunzhinan
 * @create: 2020-07-22 23:14
 * @description: 合并
 */
public class TestCompletableFuture04 {

    public static void main(String[] args) throws InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{
            System.out.println("开始获得商品1");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得商品1结束");
            return "aaa";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{
            System.out.println("开始获得商品2");
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("获得商品2结束");
            return "bbb";
        });

        CompletableFuture<String> future3 = future1.thenCombine(future2,(a,c)-> {
            System.out.println("当前线程: " + Thread.currentThread().getName());
            return a+c;
        });

        CompletableFuture<String> future4 = future1.thenCombineAsync(future2,(a,c)-> {
            System.out.println("当前线程: " + Thread.currentThread().getName());
            return a+"   "+c;
        });

       future1.thenAcceptBoth(future2,(a, c)-> {
           System.out.println("a : " + a);
           System.out.println("c : " + c);
           System.out.println("当前线程: " + Thread.currentThread().getName());
        });

        future3.thenAccept((result)->System.out.println("result3 : " + result));
        future4.thenAccept((result)->System.out.println("result4 : " + result));

        System.out.println("让主线程等待");
        TimeUnit.SECONDS.sleep(8);
        System.out.println("------OK------");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值