2.10 异步

1.实现线程的几种方式
  • 继承Thread

        public static class Thread01 extends Thread{
            @Override
            public void run() {
                System.out.println("当前线程:"+Thread.currentThread().getId());
                int i = 10/2;
                System.out.println("当前运行结果:" + i);
            }
        }
    
    
  • 继承Runable

        public static class Runnable01 implements Runnable{
     
            @Override
            public void run() {
                System.out.println("当前线程:"+Thread.currentThread().getId());
                int i = 10/2;
                System.out.println("当前运行结果:" + i);
            }
        }
    
    
  • 实现Callable接口

        public static class Callable01 implements Callable<Integer>{
     
            @Override
            public Integer call() throws Exception {
                System.out.println("当前线程:"+Thread.currentThread().getId());
                int i = 10/2;
                System.out.println("当前运行结果:" + i);
                return i;
            }
        }
    
    
  • 实现Callable接口+FutureTask

    可以得到返回值

        public static void main(String[] args) throws ExecutionException, InterruptedException {
            System.out.println("main.............start.......");
            
    //        1、继承Thread
            Thread01 thread01 = new Thread01();
            thread01.start();//启动线程
     
    //        2、实现Runnable
            Runnable01 runnable01 = new Runnable01();
            new Thread(runnable01).start();
     
    //        3、实现Callable接口+FutureTask
            FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
            new Thread(futureTask).start();
            //阻塞等待整个线程执行完成,获取返回结果
            Integer integer = futureTask.get();
     
    //        4、线程池
            service.execute(new Runnable01());
     
            System.out.println("main.............end......."+integer);
        }
    
    
  • 线程池

    也可以得到返回值,具体应用在下面介绍。

2.线程池
  • 参数解释

    corePoolSize,核心线程数[一直存在,除非(allowCoreThreadTimeOut)];线程池,创建好以后就准备就绪的线程数量,就等待接收异步任务去执行
    
    maximumPoolSize:最大线程数量;控制资源
    
    keepAliveTime:存活时间。
    
    unit:时间单位
    
    BlockingQueue<Runnable> workQueue:阻塞队列。如果任务有很多。就会将多的任务放在队列里面,只要有线程空闲,就会去队列里面取出新的任务继续执行
    
    ThreadFactory:线程创建的工厂
    
    RejectedExecutionHandler handler:如果队列满了,按照我们指定的拒绝策略,拒绝执行
    
  • 执行顺序

    • 创建线程池并初始化,准备被调用
    • 如果core线程全都在调用中,将新的任务放在阻塞队列中。core线程执行完,就会去阻塞队列中获取新的任务
    • 如果阻塞队列满了,那么就会创建新的线程执行任务,但是最大线程数量只能到maximumPoolSize
    • max也满了,就会使用拒绝策略
    • 如果max空闲了,存活时间达到keepAliveTime就会被自动释放
  • 配置形式

    @EnableConfigurationProperties(ThreadPoolConfigProperties.class)
    @Configuration
    public class MyThreadConfig {
        @Bean
        public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
            return new ThreadPoolExecutor(
                    pool.getCoreSize(),
                    pool.getMaxSize(),
                    pool.getKeepAliveTime(),
                    TimeUnit.SECONDS,
                    new LinkedBlockingDeque<>(100000),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy()
            );
        }
    }
    
  • 常见的4中线程池

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

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

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

    newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

  • 使用线程池的优点

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

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

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

3.CompletableFuture组合式异步编程

image-20230604165436093

  • 异步方法的创建

    CompletableFuture中有 runAsync 和 supplyAsync方法

    public static CompletableFuture<Void> runAsync(Runnable runnable)
    //可以指定线程池
    public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
    //可以指定线程池
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
    

    在 runAsync 和 supplyAsync方法都可以指定线程池,但是runAsync方法不支持返回值,supplyAsync方法支持返回值。

    public static void main(String[] args) throws ExecutionException, InterruptedException {
            System.out.println("main.............start.......");
        
        	//runAsync方法
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 10 / 2;
                System.out.println("当前运行结果:" + i);
            }, executor);
     
        	//supplyAsync方法
            CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 10 / 2;
                System.out.println("当前运行结果:" + i);
                return i;
            }, executor);
            Integer integer = future.get();
        
            System.out.println("main.............end......."+integer);
        }
    
  • 异步方法完成后调用方法

    提供以下的几种方法:

    //可以处理异常,无返回值
    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 CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
    

    使用:

    public class ThreadTest {
        public static ExecutorService executor = Executors.newFixedThreadPool(10);
     
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            System.out.println("main.............start.......");
     
            CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 10 / 0;
                System.out.println("当前运行结果:" + i);
                return i;
            }, executor).whenComplete((result,exception)->{
                //虽然能得到异常信息,但是没法修改返回数据
                System.out.println("异步任务完成了...结果是"+result+";异常是"+exception);
            //可以感知异常,同时返回默认值
            }).exceptionally(throwable -> {
                return 10;
            });
            Integer integer = future.get();
            
            System.out.println("main.............end......."+integer);
        }
    
  • handle方法

    handle 是执行任务完成时对结果的处理。handle 是在任务完成后再执行,还可以处理异常的任务。

    提供以下几种方法

    public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
    public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
    public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Execut
    

    实现:

    public class ThreadTest {
        public static ExecutorService executor = Executors.newFixedThreadPool(10);
     
        public static void main(String[] args) throws ExecutionException, InterruptedException {        
    		/**
             * 方法执行完成后的处理
             */
     
            CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 10 / 5;
                System.out.println("当前运行结果:" + i);
                return i;
            }, executor).handle((result,exception)->{
                if (result != null){
                    return result*2;
                }
                if (exception != null){
                    return 0;
                }
                return 0;
            });
            Integer integer = future.get();
            System.out.println("main.............end......."+integer);
        }
    

    image-20230604170746428

  • 线程串行话

    提供以下几种方法:

    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 Completionstage<void>thenAccept(Consumer<?super T>action);
    public CompletionStage<void>thenAcceptAsync(Consumer<?super T>action);
    public CompletionStage<void>thenAcceptAsync(Consumer<?super T>action,Executor
    executor);
    public Completionstage<void>thenRun(Runnable action);
    public CompletionStage<void>thenRunAsync(Runnable action);
    public Completionstage<void>thenRunAsync(Runnable action,Executor executor),
    
    • **thenRun:**不能获取上一步的执行结果
    • **thenAcceptAsync:**能接受上一步结果,但是无返回值
    • **thenApplyAsync:**能接受上一步结果,有返回值

    实现:

    public class ThreadTest {
        public static ExecutorService executor = Executors.newFixedThreadPool(10);
     
        public static void main(String[] args) throws ExecutionException, InterruptedException {  
    		 /**
             * 线程串行化
             * 1)、thenRun 不能获取得到上一步的执行结果
             */
            CompletableFuture<Void> thenRunAsync = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 10 / 5;
                System.out.println("当前运行结果:" + i);
                return i;
            }, executor).thenRunAsync(() -> {
                System.out.println("任务2启动了。。。。");
            }, executor);
     
            /**
             * 线程串行化
             * 1)、thenRun 不能获取得到上一步的执行结果,无返回值
             * 2)、thenAcceptAsync能接收上一步返回结果,但无返回值
             */
            CompletableFuture<Void> thenRunAsync = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 10 / 5;
                System.out.println("当前运行结果:" + i);
                return i;
            }, executor).thenAcceptAsync(res -> {
                System.out.println("任务2启动了。。。。"+res);
            }, executor);
     
            /**
             * 线程串行化
             * 1)、thenRun 不能获取得到上一步的执行结果,无返回值
             * 2)、thenAcceptAsync能接收上一步返回结果,但无返回值
             * 3)、thenApplyAsync能接收上一步的返回结果,也有返回值
             */
            CompletableFuture<String> thenApplyAsync = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 10 / 5;
                System.out.println("当前运行结果:" + i);
                return i;
            }, executor).thenApplyAsync(res -> {
                System.out.println("任务2启动了。。。。" + res);
                return "hello" + res;
            }, executor);
     
            System.out.println("main.............end......."+ thenApplyAsync.get());
        }
    
  • 组合-两个任务都需完成

    • runAfterBoth:两个CompletionStage,都完成了计算才会执行下一步的操作

      public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
      public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
      public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor 
      
    • thenAcceptBoth:当两个CompletionStage都执行完成后,把结果一块交给thenAcceptBoth来进行处理

      public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
      public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
      public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action,     Executor executor);
      
    • thenCombine:thenCombine 会把两个CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 处理。

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

    实现:

      	     /**
             * 不能得到两个任务的参数,也无返回结果
             */
            future01.runAfterBothAsync(future02,()->{
                System.out.println("任务三开始。。。");
            },executor);
    
            /**
             * 能得到两个任务的参数,无返回结果
             */
            future01.thenAcceptBothAsync(future02,(f1,f2)->{
                System.out.println("任务三开始。。。之前的结果"+f1+":"+f2);
            },executor);
     
            /**
             * 能得到两个任务的参数,无返回结果
             */
            CompletableFuture<String> thenCombineAsync = future01.thenCombineAsync(future02, (f1, f2) -> {
                System.out.println("任务三开始。。。之前的结果" + f1 + ":" + f2);
                return f1 + ":" + f2 + "->haha";
            }, executor);
            System.out.println("main.............end......." + thenCombineAsync.get());
        }
    

    image-20230604171936888

  • 组合-两个任务只需要其中一个完成

    • runAfterEither:两个CompletionStage,任何一个完成了都会执行下一步的操作

      public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);
      public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);
      public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);
      
      
    • acceptEither:两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行处理

      public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
      public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
      public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? supe
      
      
    • applyToEither:两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的转化操作

      public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
      public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
      public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? sup
      
      
    • thenCompose:允许对两个 CompletionStage 进行流水线操作,第一个操作完成时,将其结果作为参数传递给第二个操作

      public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);
      public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) ;
      public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage
      
      
  • 多任务组合

    • allOf:等待所有任务完成后进行下一步

       CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
                  System.out.println("查询商品的属性");
                  return "黑色+256g";
              },executor);
       
              CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
                  try {
                      Thread.sleep(3000);
                      System.out.println("查询商品的图片信息");
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  return "hello.jpg";
              },executor);
       
              CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
                  System.out.println("查询商品的介绍");
                  return "华为";
              },executor);
              CompletableFuture<Void> allOf = CompletableFuture.allOf(futureAttr, futureImg, futureDesc);
              allOf.get();//等待所有线程执行完
              System.out.println("main.............end......."+futureAttr.get()+"=>"+futureImg.get()+"=>"+futureDesc.get() );
          }
      

      image-20230604172611399

    • anyOf:只要其中有一个任务完成即可执行下一步

      CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
                  System.out.println("查询商品的属性");
                  return "黑色+256g";
              },executor);
       
              CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
                  try {
                      Thread.sleep(3000);
                      System.out.println("查询商品的图片信息");
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  return "hello.jpg";
              },executor);
       
              CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
                  System.out.println("查询商品的介绍");
                  return "华为";
              },executor);
      //        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureAttr, futureImg, futureDesc);
      //        allOf.get();//等待所有线程执行完
              CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureAttr, futureImg, futureDesc);
              System.out.println("main.............end......."+anyOf.get() );
      

      image-20230604172702735

总结

本篇我们介绍了有关异步的常用知识,包括线程的创建、线程池、CompletableFuture的使用,在项目中需要根据具体情况决定如何使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值