线程异步编排-线程池

线程异步编排-线程池

1.初始化线程的4种方式

1).继承Thread接口

2).实现Runnable接口

3).实现Callable接口 + FutureTask(可以拿到返回结果,可以批量处理) JDK1.5加入

4).线程池[将所有的多线程任务都交给线程池执行] Future可以获取到异步结果

方式1和方式2:主线程无法获取线程的运算结果,不适合当前场景

方式3:主线程可以获取线程的运算结果,但是不利于控制服务器中的线程资源,可以导致服务器资源耗尽

方式4:通过如下两种方式初始化线程池

Executors.newFiexedThreadPool(3);
//或者
new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit unit,workQueue,threadFactory,handler);

//线程池控制资源,性能稳定
public static ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new Runnable01());

通过线程池性能稳定,也可以获取执行结果,并捕获异常,但是,在业务复杂的情况下,一个异步调用可能会依赖于另一个异步调用的执行结果

ThreadPoolExecutor executor=new ThreadPoolExecutor();
//七大参数
corePoolSize    核心线程数[一直存在,除非(allowCoreThreadTimeOut)]:线程池创建好以后就准备就绪的线程数量,就等待来接收异步任务去执行
             5Thread thread = new  Thread();  thread.start();
maximumPoolSize  最大线程数:控制资源并发
keepAliveTime    存活时间,如果当前线程数量大于核心线程数释放空闲线程(maximumPoolSize-corePoolSize),只要线程空闲大于指定的keepAliveTime
unit              时间单位
BlockingQueue<Runnable> workQueue   阻塞队列:如果任务有很多,就会将目前多的任务放在队列中里面只要有线程空闲,就会去队列里面取出新的任务继续执行
threadFactory    线程的创建工厂
RejectedExecutionHandler handler    如果队列满了,按照我们指定的拒绝策略拒绝执行任务

//new LinkedBlockingQueue<>(10000) 默认是Integer的最大值 指定线程数量/压力测试得到
        ThreadPoolExecutor executor=
                new ThreadPoolExecutor(5,
                        200,
                        10,
                        TimeUnit.SECONDS,
                        new LinkedBlockingQueue<>(10000),
                        Executors.defaultThreadFactory(),
                        new ThreadPoolExecutor.AbortPolicy()
        );

运行流程:

1.线程池创建,准备好core数量的核心线程,准备接受任务

2.新的任务进来,用core准备好的空闲线程执行

​ (1)core满了,就将再进来的任务放入阻塞队列中,空闲的core就会自己去阻塞队列获取任务执行

​ (2)阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量

​ (3)max都执行好了,Max-Core数量空闲的线程会在keepAllveTime指定的时间后会自动销毁,最终保持到core大小

​ (4)如果线程数开到max的数量,还有新任务进来,就会使用reject指定的拒绝策略进行处理

如果不想抛弃还要执行,CallerRunsPolicy拒绝策略

2.常见的4种线程池[Executors]

newCacheThreadPool core是0,所有都可回收

​ 创建一个可缓存线程池,如果线程长度超过处理需要,可灵活回收空闲线程,若无法回收,则创建新的线程

newFixedThreadPool 固定大小,coremax,都不可回收

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

newScheduledThreadPool 定时任务的线程池

创建一个定长线程数,支持定时及周期性任务执行

newSingleThreadExecutor 单线程的线程池,后台从队列里面按顺序挨个执行任务

串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行

3.开发中为什么使用线程池

降低资源的损耗

通过重复利用已经创建好的线程降低线程的创建和销毁带来的资源消耗

提高响应速度

因为线程池中的线程数没有超过线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行

提高线程的可管理性

线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销,无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配

异步编排 CompletableFuture JDK1.8加入

业务场景

查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必须花费更多的时间

//获取sku的基本信息		0.5s
//获取sku的图片信息		0.5s
//获取sku的促销信息		1s
//获取spu的所有销售属性	   1s
//获取规格参数组以及组下的规格参数	1.5s
//spu详情					1s

假如商品详情页的每个查询,需要如下标往的时间才能完成

那么,用户需要6.5s后才能看到商品详情页的内容。很显然是不能接受的。

如果有多个线程同时完成这6步操作,也许只需要1.55 即可完成响应。

1.创建异步对象

CompletableFuture 提供了四个静态方法来创建一个异步操作

static CompletableFuture<void> runAsync(Runnable runnab1e)
public static CompletableFutur e<Void> runasync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyasync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync (Supplier<U> supplier, Executorexecutor )  

1、runXxox都是没有返回结果的,supplyXx 都是可以获取返回结果的

2、可以传入自定义的线程池,否则就用默认的线程池;

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("开始.........");
        /*CompletableFuture future = CompletableFuture.runAsync(() -> {
            System.out.println("当前线程ID:  " + Thread.currentThread().getId());
            int count = 10 / 2;
            System.out.println("运行结果:  " + count);
        }, executor);*/
        //不接受入参,只有返回值
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程ID:  " + Thread.currentThread().getId());
            int count = 10 / 2;
            System.out.println("运行结果:  " + count);
            return count;
        }, executor);
        System.out.println("结束........."+future.get());
    }

2.计算完成时回调方法

public CompletableFuture<T> whenC omplete(BiConsumer<? super T,7 super Throwable> action);
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,7 super Thr owable> action);
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,7 super Thr owable> action, Executor executor);
public CompletableFuture<T> except ionally(Funct ion<Throwable,7 extends T> fn);

whenComplete可以处理正常和异常的计算结果,exceptionally 处理异常情况。

whenComplete和whenCompleteAsync 的区别:

​ whenComplete:是执行当前任务的线程执行继续执行whenComplete的任务。

​ whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行。

方法不以Asyne结尾,意味着Action使用相同的线程执行,而Asyne可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("开始.........");
        //不接受入参,只有返回值	方法完成后的感知
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程ID:  " + Thread.currentThread().getId());
            int count = 10 / 0;
            System.out.println("运行结果:  " + count);
            return count;
        }, executor).whenComplete((res,excption)->{
            //虽然能得到返回信息,但是没法修改返回数据
            System.out.println("异步任务成功完成了.....结果是:"+res+"异常是:"+excption);
        }).exceptionally(throwable -> {
            //可以感知异常,同时返回默认值
            //R apply(T t);
            return 10;
        });
        System.out.println("结束........."+future.get());
    }

3.handle方法

public <U> Complet ionstage<U>handle (BiFunction<? super T, Throwable, ? extends U> fn);
public <U> Complet ionStage<U> handleasync(BiFunction<? super T, Throwable. ? extends U> fn);
public <U> Complet ionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor);
//handle方法 方法执行完成后的处理
	 public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("开始.........");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程ID:  " + Thread.currentThread().getId());
            int count = 10 / 4;
            System.out.println("运行结果:  " + count);
            return count;
        }, executor).handle((res,thr)->{
            if(res!=null){
                return res*2;
            }
            if(thr!=null){
                return 0;
            }
            return  0;
        });
        // R apply(T t, U u);
        System.out.println("结束........."+future.get());
    }

和complete一样,可对结果做最后的处理(可处理异常),可改变返回值。

4.线程串行化方法

public  CompletableFuture thenApply(Function fn)
public  CompletableFuture thenApplyAsync(Function fn)
public  Complet ableFuture thenapplyAsync(Function fn,Executor executor)

public CompletionStage thenaccept (Consumer action) ;
public CompletionStage thenacceptAsync (Consumer action) ;
public CompletionStage thenAcceptAsync(Consumer act ion, Executorexecutor);

public Completi onStage thenRun(Runnable action) ;
public CompletionStage thenRunAsync (Runnable action);
public CompletionStage thenRunAsync (Runnable action,Executor executor);

thenApply方法:当-一个线程依赖另-一个线程时,获取上一一个任务返回的结果,并返回当前任务的返回值。

thenAccept方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。

thenRun方法:只要上面的任务执行完成,就开始执行thenRun,只是处理完任务后,执行

thenRun的后续操作带有Async默认是异步执行的。同之前。

以上一个任务返回结果的类型

Function

T:上一个任务返回结果的类型

U:指定线程池

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("开始.........");
        /**
         * 线程串行化
         * 1.thenRunAsync   不能获取上一步的执行结果,无返回值
         *          .thenRunAsync(() -> {
         *             System.out.println("任务2启动了....");
         *         }, executor);
         * 2.thenAcceptAsync 能接受上一步结果,但是无法使用返回参数
         *          .thenAcceptAsync(res ->{
         *             System.out.println("任务2启动了...."+res);
         *         },executor);
         * 3.thenApplyAsync 能接受上一步结果,也可以使用返回值
         *          .thenApplyAsync(res -> {
         *             System.out.println("任务2启动了...." + res);
         *             return "Hello Word--->" + res;
         *         }, executor);
         */
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程ID:  " + Thread.currentThread().getId());
            int count = 10 / 4;
            System.out.println("运行结果:  " + count);
            return count;
        }, executor).thenApplyAsync(res -> {
            System.out.println("任务2启动了...." + res);
            return "Hello Word--->" + res;
        }, executor);
        //R apply(T t);
        System.out.println("结束........."+future.get());
    }

5.两任务组合-都要完成

public <U,V> Complet ableFuture<V> thenCombine(CompletionStage<? extends U> other BiFunction<? super T,? super U,? extends V> fn) ;
public <U,V> CompletableFuture<V> thenCombineAsync(Complet ionStage<? extends U> other ,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other ,BiFunction<? super T,? super U,? extends V> fn, Executor executor);


public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other ,BiConsumer<? super T? super U> action);
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other ,BiConsumer<7 super T? super U> action) ;
public <U> Complet ab1 eFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other ,BiConsumer<? super T? super U> action, Executor executor) ;


public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
public CompletableFuture<Void> runAfterBothsync(CompletionStage<?> other ,Runnable action);
pub1ic CompletableFuturecvoid runAfterBothAsync(Completionstage<?> other ,Runnable action,Executor executor):

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

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

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

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

  public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("开始.........");
        /**
         * 两个都完成
         */
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1开始:  " + Thread.currentThread().getId());
            int count = 10 / 4;
            System.out.println("任务1运行结果:  ");
            return count;
        }, executor);

        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2开始:  " + Thread.currentThread().getId());
            System.out.println("任务2执行结果:  ");
            return "Hello";
        }, executor);

        /*future01.runAfterBothAsync(future02,()->{
            System.out.println("任务3开始");
        },executor);*/      //不能获取前两者的返回值,不能更改返回值

       /* future01.thenAcceptBothAsync(future02,(f1,f2)->{
            //void accept(T t, U u);
            System.out.println("任务3开始...之前的结果:"+f1 +"--->"+f2);
        },executor);*/      //可以获取前两者的返回指,不能更改返回指

        /*CompletableFuture future = future01.thenCombineAsync(future02, (f1, f2) -> {
            //R apply(T t, U u);
            return f1 + ": " + f2 + "->HaHa";
        }, executor);*/		//可以获取前两者的返回指,可以更改返回指
        System.out.println("结束........."+future.get());
    }

6.两任务组合-一个完成

public <U> Complet ableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn);
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<7 super T, U> fn);
public <U> Complet ableFuture<U> applyToEitherAsyne(CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor); 

public Complet ableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action);
public Complet ableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action);
public Complet ableFutur e<Voids acceptEitherAsync(CompletionStage<? extends T> other, Consuser<? super T> action,Executor ; executor);

public CorpletableFuture<Void> runAfterEither (Completionstage<7> other,Runnable action);
public CorpletableFuture<Void> runAfterEitherAsync(Complet ionStage<7> other ,Runnable action);
public ComrpletableFuture<Void> runAfterEitherAsyne(Complet ionstage<7> other ,Runnable action,Executor executor);

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

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

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

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

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("开始.........");	   		
		/**
         * 两个都有一个完成
         */
        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1开始:  " + Thread.currentThread().getId());
            int count = 10 / 4;
            System.out.println("任务1运行结果:  ");
            return count;
        }, executor);

        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2开始:  " + Thread.currentThread().getId());
            try {
                Thread.sleep(3000);
                System.out.println("任务2执行结果:  ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello";
        }, executor);

        /**
         * 两个任务只要有一个完成就执行任务3
         * runAfterEitherAsync  不能获取前两者的返回值,不能更改返回值
         * acceptEitherAsync    可以获取前两者的返回值,不能更改返回值(要求返回值是相同的)
         * applyToEitherAsync	可以获取前两者的返回值,可以更改组合返回值(要求返回值是相同的)
         */
       /* future01.runAfterEitherAsync(future02,()->{
            System.out.println("任务3开始");
        },executor);*/
       /* future01.acceptEitherAsync(future02,(res)->{
            //void accept(T t);
            System.out.println("任务3开始-->"+res);
        },executor);*/
        CompletableFuture<String> future = future01.applyToEitherAsync(future02, (res) -> {
            return res.toString() + "->哈哈";
        }, executor);
        System.out.println("结束........."+future.get());

7.多任务组合

public static Complet ableFuture<Void> a11of(Comp1etableFuture<?>... cfs);
public static CompletableFuturecobject> anyof(CompletableFuture<?>... cfs);

allof:等待所有任务完成

anyOf:只要有一个任务完成,就返回第一个完成的线程返回值

  public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("开始.........");
        /**
         * 多任务组合
         */
        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        }, executor);
        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256G";
        }, executor);
        CompletableFuture<String> futurDesc = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("查询商品介绍信息");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "华为Mate30 Pro";
        }, executor);

       /* CompletableFuture allOf = CompletableFuture.allOf(futureImg, futureAttr, futurDesc);
        allOf.join();   //等待所有结果完成
        System.out.println("结束........."+futureImg.get() +"---"+futureAttr.get()+"---"+futurDesc.get());*/

        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futurDesc);
        anyOf.get();   //只要有一个任务完成,就返回第一个完成的线程返回值
        System.out.println("结束........."+ anyOf.get());
  }

面试:

一个线程池core7;max20;queue50;100并发进来怎么分配的?

先有7个能直接得到执行,接下来50个进入队列,在多开13个继续执行,现在70个被安排上了,剩下的30个默认拒绝策略

你可能感兴趣的:(java)