异步与多线程

一 初始化线程的四种方式

  1. 继承Thread
  2. 实现Runnable
  3. 实现Runnable接口+FutureTask
  4. 线程池

二 线程池是什么?

线程池类似数据库连接池,在线程池中,总有那么几个活跃的线程。当你需要使用线程时,可以从池子中随便拿一个空闲的线程使用,待完成工作,将线程归还给线程池。

三 线程池的分类

1.Executors

Executors类扮演着线程工厂的角色,使用该类的静态方法可以获取特点功能的线程池。

1.1 newFixedThreadPool()

该方法返回固定线程数量的线程池。LinkedBlockingQueue

public static class MyTask implements Runnable{

        @Override
        public void run() {
            //获取当前时间的毫秒数+:Thread Id:+当前线程的Id作为标识
            String threadName = System.currentTimeMillis()+
                    ":Thread Id:"+Thread.currentThread().getId();
            System.out.println(threadName+"start");
            try {
                //sleep()不会释放锁,wait会释放锁
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName+"end");
        }
    }

	public static void main(String[] args) {
        MyTask task = new MyTask();
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        System.out.println("main:"+Thread.currentThread().getId()+"start");
        for(int i=0;i<10;i++){
            executorService.submit(task);
        }
        System.out.println("main:"+Thread.currentThread().getId()+"end");
    }

main:1start
1604731505456:Thread Id:11start
1604731505456:Thread Id:12start
1604731505456:Thread Id:12end
1604731506473:Thread Id:12start
1604731505456:Thread Id:11end
1604731506473:Thread Id:12end
main:1end

1.2 newSingleThreadExecutor()

该方法返回一个只有一个线程的线程池。LinkedBlockingQueue

1.3 newCachedThreadPool()

该方法返回一个可根据实际情况调整线程数量的线程池。当开启10个线程时,通过id可知,线程池中加有10个线程,该方法会根据cpu的资源占用自动调整线程池的大小。SynchronousQueue

public static void main(String[] args) {
        MyTask task = new MyTask();
        ExecutorService executorService = Executors.newCachedThreadPool();
        System.out.println("main:"+Thread.currentThread().getId()+"start");
        for(int i=0;i<10;i++){
            executorService.submit(task);
        }
        try {
            Thread.sleep(5000);
            System.out.println("main:"+Thread.currentThread().getId()+"end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
1.4 newSingleThreadScheduledExecutor()

该方法返回一个ScheduledExecutorService对象,线程池大小为1。可以实现线程周期性执行和延迟执行。

1.5 newScheduledThreadPool()

该方法返回一个ScheduledExecutorService对象,可指定线程池的线程数量。

/**
command:任务
delay:延迟时间
TimeUnit:单位 给定单元粒度的时间段
**/
schedule(Runnable command,long delay, TimeUnit unit);
/**
command:任务
initialDelay:初始延迟时间
period:周期的时间
unit:单位
第一次:initialDelay+0*period
第二次:initialDelay+1*period
...
**/
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
/**
command:任务
initialDelay:初始延迟时间
delay:延迟时间
第一次:initialDelay
第二次:第一次的结束时间+delay
**/
scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)

注意:任务遇到异常,后续的所有子任务都会停止调度。

四 ThreadPoolExecutor

以上介绍的线程池都是基于ThreadPoolExecutor类的封装

ThreadPoolExecutor(int corePoolSize,//指定线程池中的线程数量
                   int maximumPoolSize,//指定线程池中的最大线程数
                   long keepAliveTime,
                   /**
                   当线程池中的线程数超过corePoolSize,
                   多余空闲线程的存活时间
                   **/
                   TimeUnit unit,//时间单位
                   BlockingQueue<Runnable> workQueue,//任务队列
                   ThreadFactory threadFactory,//线程工厂
                   RejectedExecutionHandler handler)//决绝策略
3.1BlockingQueue

workQueue:提交但未执行的任务队列。

  • SynchronousQueue:直接提交的队列(不会真实的存储任务,都会交给线程执行,没有空闲线程时执行拒绝策略)
  • ArrayBlockingQueue:有界的任务队列。当新任务执行,若实际线程数少于corePoolSize,优先创建新线程,若大于corePoolSize,将任务加入等待队列。若队列已满,无法加入,若总线程<maximumPoolSize,创建新的线程,否则,执行拒绝策略。
  • LinkedBlockingQueue:无界的任务队列。
  • PriorityBlockingkQueue:优先任务队列。可以控制任务的执行先后顺序,类似无界任务队列,可以根据任务自身的优先级先后执行。
3.2 RejectedExecutionHandler

handler:拒绝策略,当任务数量超过了系统的负载,就会使用到拒绝策略。

  • AbortPolicy策略:直接抛出异常,阻止系统正常工作。
  • CallerRunsPolicty策略:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。
  • DiscardOldPolicty策略:该策略会丢弃即将执行的任务,并尝试再次提交任务。
  • DiscardPolcty策略:默默丢弃无法处理的任务。

ThreadFactory:线程工厂是一个接口。只定义了一个用来创建线程的方法。

public interface ThreadFactory {
	Thread newThread(Runnable r);
}

五 扩展线程池

ThreadPoolExecutor 是一个可以扩展的线程池。它提供了beforeExecutor()、afterExecutor()/terminated()三个接口用来对线程池进行控制。

public class MyThreadPool {
    public static class MyTask implements Runnable{
        private String name;

        public MyTask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            System.out.println("正在执行"+":Thread Id"+Thread.currentThread().getId()
            +",Task Name"+name);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService es = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>()){
            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                System.out.println("准备执行:"+((MyTask) r).name);
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                System.out.println("执行完成:"+((MyTask) r).name);
            }

            @Override
            protected void terminated() {
                System.out.println("线程池退出");
            }
        };

        for(int i=0;i<5;i++){
            MyTask myTask = new MyTask("Task"+i);
            es.execute(myTask);
            Thread.sleep(10);
        }
        es.shutdown();
    }
}

线程池的优势

  • 降低资源的消耗
    • 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
  • 提高响应速度
    • 因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
  • 提高线程的可管理性
    • 线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配

CompletableFuture 异步编排

在这里插入图片描述

以下example都采用如下线程池

public static ExecutorService executor = Executors.newFixedThreadPool(10);
1 runAsync 异步执行,不带返回结果
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)
public static void main(String[] args) {
    log.info("main 线程开始-----------------------");
    CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
        log.info("当前线程:"+Thread.currentThread().getName()+"开始-----------------------");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("当前线程:"+Thread.currentThread().getName()+"结束-----------------------");
    },executor);
    log.info("main 线程结束-----------------------");

}

在这里插入图片描述

2 supplyAsync 异步执行,带返回结果
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)
public static void main(String[] args) throws ExecutionException, InterruptedException {
        log.info("main 线程开始-----------------------");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
            int result = 100 / 2;
            log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
            return result;
        }, executor);
        log.info("main 线程结束----------------------- result="+future.get());

    }

在这里插入图片描述

3 whenComplete 成功回调
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)
public static void main(String[] args) throws ExecutionException, InterruptedException {
        log.info("main 线程开始-----------------------");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
            //int result = 100 / 2;
            int result = 1/0;
            log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
            return result;
        }, executor).whenComplete((res,exception)->{
            log.info("调用成功,返回结果是:"+res+" 异常是:"+exception);
        });
        log.info("main 线程结束-----------------------");

    }

在这里插入图片描述

在这里插入图片描述

4 exceptionally 异常回调
CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
public static void main(String[] args) throws ExecutionException, InterruptedException {
        log.info("main 线程开始-----------------------");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
            //int result = 100 / 2;
            int result = 1/0;
            log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
            return result;
        }, executor).whenComplete((res,exception)->{
            log.info("调用成功,返回结果是:"+res+" 异常是:"+exception);
        }).exceptionally(throwable -> 10);
        log.info("main 线程结束-----------------------"+future.get());

    }

在这里插入图片描述

5 handle 方法执行完后处理
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)

public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)

public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)
public static void main(String[] args) throws ExecutionException, InterruptedException {
    log.info("main 线程开始-----------------------");
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
        int result = 100 / 2;
        //int result = 1/0;
        log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
        return result;
    }, executor).handle((res,exception)->{
        //res 结果 exception 异常
        if(res!=null){
            return res;
        }
        if(exception!=null){
            return 0;
        }
        return 0;
    });
    log.info("main 线程结束-----------------------"+future.get());

}

在这里插入图片描述
在这里插入图片描述

6 线程串行化方法
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) 

public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)

public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
    
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)

public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)

public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor)
    
public CompletableFuture<Void> thenRun(Runnable action)

public CompletableFuture<Void> thenRunAsync(Runnable action)

public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)

thenRun 同样线程执行B任务,无返回值,不能接收上一步返回的结果

log.info("main 线程开始-----------------------");
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
    log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
    int result = 100 / 2;
    log.info("A任务开始执行");
    //int result = 1/0;
    log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
    return result;
}, executor).thenRun(()->{
    log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
    int result = 100 / 2;
    log.info("B任务开始执行");
    //int result = 1/0;
    log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
});
log.info("main 线程结束-----------------------"+future.get());

在这里插入图片描述

thenRunAsync 开启新线程执行B任务,无返回值,不能接收上一步返回的结果

log.info("main 线程开始-----------------------");
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
    log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
    int result = 100 / 2;
    log.info("A任务开始执行");
    //int result = 1/0;
    log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
    return result;
}, executor).thenRunAsync(()->{
    log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
    int result = 100 / 2;
    log.info("B任务开始执行");
    //int result = 1/0;
    log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
},executor);
log.info("main 线程结束-----------------------"+future.get());

在这里插入图片描述

7 两任务组合 - 都要完成
public <U,V> CompletableFuture<V> thenCombine(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn) {
    return biApplyStage(null, other, fn);
}

public <U,V> CompletableFuture<V> thenCombineAsync(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn) {
    return biApplyStage(asyncPool, other, fn);
}

public <U,V> CompletableFuture<V> thenCombineAsync(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
    return biApplyStage(screenExecutor(executor), other, fn);
}

public <U> CompletableFuture<Void> thenAcceptBoth(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action) {
    return biAcceptStage(null, other, action);
}

public <U> CompletableFuture<Void> thenAcceptBothAsync(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action) {
    return biAcceptStage(asyncPool, other, action);
}

public <U> CompletableFuture<Void> thenAcceptBothAsync(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action, Executor executor) {
    return biAcceptStage(screenExecutor(executor), other, action);
}

两个任务必须都完成,触发该任务。

thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值

thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有

返回值。

runAfterBoth:组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后,

处理该任务。

8 两任务组合 - 一个完成
public <U> CompletableFuture<U> applyToEither(
    CompletionStage<? extends T> other, Function<? super T, U> fn) {
    return orApplyStage(null, other, fn);
}

public <U> CompletableFuture<U> applyToEitherAsync(
    CompletionStage<? extends T> other, Function<? super T, U> fn) {
    return orApplyStage(asyncPool, other, fn);
}

public <U> CompletableFuture<U> applyToEitherAsync(
    CompletionStage<? extends T> other, Function<? super T, U> fn,
    Executor executor) {
    return orApplyStage(screenExecutor(executor), other, fn);
}
public CompletableFuture<Void> acceptEither(
    CompletionStage<? extends T> other, Consumer<? super T> action) {
    return orAcceptStage(null, other, action);
}

public CompletableFuture<Void> acceptEitherAsync(
    CompletionStage<? extends T> other, Consumer<? super T> action) {
    return orAcceptStage(asyncPool, other, action);
}

public CompletableFuture<Void> acceptEitherAsync(
    CompletionStage<? extends T> other, Consumer<? super T> action,
    Executor executor) {
    return orAcceptStage(screenExecutor(executor), other, action);
}

public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
                                              Runnable action) {
    return orRunStage(null, other, action);
}

public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
                                                   Runnable action) {
    return orRunStage(asyncPool, other, action);
}

public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
                                                   Runnable action,
                                                   Executor executor) {
    return orRunStage(screenExecutor(executor), other, action);
}

当两个任务中,任意一个 future 任务完成的时候,执行任务。

applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。

acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。

runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返

回值。

9 多任务组合
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
    
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)

allOf:等待所有任务完成

anyOf:只要有一个任务完成

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值