异步与线程池

本文详细介绍了Java中线程池的初始化方式、ThreadPoolExecutor的七大参数及其任务执行流程,探讨了四种常见的线程池类型。此外,文章还深入讲解了CompletableFuture的异步编排,包括创建异步对象、回调方法、处理结果的多种方式,以及多任务的组合策略,展示了在商品详情页优化中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、初始化线程的4种方式

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口+FutureTask(可以拿到返回结果,可以进行异常处理)
  4. 线程池
  • 继承Thread类和实现Runnable接口:主进程无法获取线程的运算结果。
  • 实现Callable接口:主进程可以获取线程的运算结果,但是不利于控制服务器种的线程资源,可能导致服务器资源耗尽。
  • 线程池:初始化方式
 //初始化线程池
 ExecutorService executorService = Executors.newFixedThreadPool(3);

ThreadPoolExecutor(int corePoolSize,
                  int maximumPoolSize,
                  long keepAliveTime,
                  TimeUnit unit,
                  BlockingQueue<Runnable> workQueue,
                  ThreadFactory threadFactory,
                  RejectedExecutionHandler handler) 

二、new ThreadPoolExecutor()七大参数

在这里插入图片描述

  1. corePoolSize:线程池种一致保持的线程数量。
  2. maximumPoolSize:线程池种允许最大的线程数。
  3. keepAliveTime:当线程数大于核心线程数的时候,超出核心线程数的线程在最大多长时间没有接到新任务就会终止释放,最终线程池维持在corePoolSize大小。
  4. unit:时间单位。
  5. workQueue:阻塞队列,用来存储等待执行的任务,如果当前对线程的需求超过了corePoolSize大小,就会放在这里等待空闲线程来执行。
  6. threadFactory:创建线程的工厂,比如指定线程名等等。
  7. handler:拒绝策略。如果线程满了,线程池就会使用拒绝策略。

三、线程池运行任务的流程

1.流程

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

  2. 新的任务进来,用core准备好的空闲线程执行。
    1)core满了,就将再来的任务加入到阻塞队列种。空闲的core就会到阻塞队列中获取任务执行。
    2)阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量。
    3)max都执行好了。max-core数量空闲的线程就会在keepAliveTime指定的时间后自行销毁。最终保持到core的大小
    4)如果线程开打max的数量,还是有新任务进来,就会使用reject指定的拒绝策略进行处理。

  3. 所有的线程创建都是由指定的threadFactory创建。

2.面试题

一个线程池 core=7;max=20;queue=50。那100个并发请求进来是怎么分配的?
先有7个请求能直接得到执行,接下来50个进入阻塞队列,在多开13(20-7)个线程继续执行请求任务。现在总过有7+13+50=70个任务被安排上了。剩余的30个默认执行拒绝策略。

四、常见的4种线程池

  1. newCacheThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,如无可回收,则新建线程。
  2. newFixedThreadPool:创建一个定长线程池,可以控制线程最大并发数,超出的线程回在队列种等待。
  3. newScheduledThreadPool:创建一个定长线程池,支持定时以及周期性任务执行。
  4. newSingleThreadExecutor:创建一个单线程的线程池,只会用唯一一个工作线程来执行任务,保证所有任务按照指定顺序执行。

五、CompletableFuture异步编排

在java8中,新增了一个包含50个方法左右的类,CompletableFuture,提供了非常强大的Future扩展功能,可以帮助简化异步编程的复杂性,提供了函数式编程的能力。可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法。CompletableFuture类实现了Future接口,所以还是以通过get()方法阻塞或者轮询的方式获得结果。

1.CompletableFuture创建异步对象

CompletableFuture有四个静态方法来创建异步操作。
在这里插入图片描述

public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

public static CompletableFuture<Void> runAsync(Runnable runnable)

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

runAsync方法都是没有返回值的,supplyAsync都是可以获取返回结果的。
都可以传入自定义的线程池,否则就用默认的线程池。

2.计算完成时回调方法(whenComplete、exceptionally)

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

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)

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

  1. whenComplete:是执行当前任务的线程继续执行whenComplete的任务。
  2. whenCompleteAsync:把执行whenCompleteAsync的任务继续提交给线程池来执行。(可能开启新的线程。)
public static void main(String[] args) throws ExecutionException, InterruptedException {
   
  CompletableFuture future = CompletableFuture.supplyAsync(new Supplier<Object>() {
   
      @Override
      public Object get() {
   
          System.out.println(Thread.currentThread() + " ---- completableFuture");
          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值