java自定义线程池的使用与异步编排

一,线程池的七大参数介绍:

    

  public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
 1)corePoolSize:核心线程数[一直存在],线程池创建好后就绪的线程数量,就等待来接收异步任务去执行
 2)setMaximumPoolSize,最大线程数
 3)setKeepAliveTime,存活时间:当前线程数量大于核心数量,线程空闲之后存活的时间 ,释放空闲的线程
 4)TimeUnit,时间单位
 5)BlockingQueue<Runnable>,阻塞队列,如果任务很多,就会将目前多的任务放在队列里,只要有空闲的线程,
        就会去队列里面取出新的任务继续执行
 6)threadFactory:线程的创建工厂
 7)setRejectedExecutionHandler:如果队列满了,按照我们指定的拒绝策略,拒绝执行任务,4种拒绝策略
  • 第一种拒绝策略是 AbortPolicy,这种拒绝策略在拒绝任务时,会直接抛出异常 RejectedExecutionException (属于RuntimeException),让你感知到任务被拒绝了,于是你便可以根据业务逻辑选择重试或者放弃提交等策略。
  • 第二种拒绝策略是 DiscardPolicy,这种拒绝策略正如它的名字所描述的一样,当新任务被提交后直接被丢弃掉,也不会给你任何的通知,相对而言存在一定的风险,因为我们提交的时候根本不知道这个任务会被丢弃,可能造成数据丢失。
  • 第三种拒绝策略是 DiscardOldestPolicy,如果线程池没被关闭且没有能力执行,则会丢弃任务队列中的头结点,通常是存活时间最长的任务,这种策略与第二种不同之处在于它丢弃的不是最新提交的,而是队列中存活时间最长的,这样就可以腾出空间给新提交的任务,但同理它也存在一定的数据丢失风险。
  • 第四种拒绝策略是 CallerRunsPolicy,相对而言它就比较完善了,当有新任务提交后,如果线程池没被关闭且没有能力执行,则把这个任务交于提交任务的线程执行,也就是谁提交任务,谁就负责执行任务。这样做主要有两点好处。
    • 第一点新提交的任务不会被丢弃,这样也就不会造成业务损失。
    • 第二点好处是,由于谁提交任务谁就要负责执行任务,这样提交任务的线程就得负责执行任务,而执行任务又是比较耗时的,在这段期间,提交任务的线程被占用,也就不会再提交新的任务,减缓了任务提交的速度,相当于是一个负反馈。在此期间,线程池中的线程也可以充分利用这段时间来执行掉一部分任务,腾出一定的空间,相当于是给了线程池一定的缓冲期。

  

二:

  1、自定义线程参数配置类,可以在配置文件中配置前三个参数

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@ConfigurationProperties(prefix = "custom.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
    //核心线程数
    private Integer coreSize;
    //最大线程数
    private Integer maxSize;
    //存活时间
    private Integer keepAliveTime;
}

2、在线程的配置中自定义一个线程池并加入到容器中:

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
public class MyThreadConfig {
    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties threadPoolConfigProperties){
        return new ThreadPoolExecutor(threadPoolConfigProperties.getCoreSize(),
                threadPoolConfigProperties.getMaxSize(),
                threadPoolConfigProperties.getKeepAliveTime(),
                TimeUnit.SECONDS ,
                new LinkedBlockingDeque<>(10000),
                Executors.defaultThreadFactory(),
                new  ThreadPoolExecutor.AbortPolicy());
    }
}

3、在异步编排中使用线程池

   1、

CompletableFuture.runAsync 无法感知到方法完成,也没返回结果
 public static ExecutorService executor = Executors.newFixedThreadPool(10);
    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            int i = 1+1;
            System.out.println("运行结果:" + i);
        }, executor);

2、

 CompletableFuture.supplyAsync  可以感知到方法完成,无返回结果
whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况。
whenComplete 和 whenCompleteAsync 的区别:
      whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
      whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池
来进行执行。
方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程
执行(如果是使用相同的线程池,也可能会被同一个线程选中执行
handle和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值
 CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 1 + 1;
            return i;
        }, executor).whenComplete((result, exc) -> {
            System.out.println("异步任务成功完成,结果为" + result + ";异常为" + exc);
        }).exceptionally(throwable -> 0);//感知异常,返回默认值
       CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 1 + 1;
            return i;
        }, executor).handle((result,thr)->{
            if(result!=null){
                return  result*2;
            }
            if(thr!=null){
                return  1;
            }
            return 0;
        });

3、线程的串行化

1)thenrun:不能获取到上一步的执行结果,无返回值
      thenRunAsync(() -> {
         System.out.println("任务2启动");
     }, executor);
2)thenAccept:可以获取到上一步的执行结果,无返回值
      thenAcceptAsync((res) -> {
         System.out.println("任务2启动" + res);
     }, executor);
3) thenApply:可以获取到上一步的执行结果,有返回值
      thenApplyAsync((res) -> {
         System.out.println("任务2启动" + res);
         return res;
     }, executor);
  CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            int i = 1 + 1;
            return i;
        }, executor).thenApplyAsync((res) -> {
            System.out.println("任务2启动" + res);
            return res * 3 + "";
        }, executor);

4、线程的组合任务

both:两个线程均需要完成,either:只要任意一个完成就可以

 runAfterBothAsync,runAfterEitherAsync       不感知结果,无返回值
 thenAcceptBothAsync,acceptEitherAsync       感知结果,无返回值
 thenCombineAsync,applyToEitherAsync         感知结果,有返回值

新建两个线程

  CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            int i =1+1;
            System.out.println("任务1线程结束");
            return i;
        }, executor);

        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务2线程结束");
            return "hello";
        }, executor);
//任务1与任务2均结束,则执行任务3,任务3获取不到任务1与任务2的执行结果,任务3没有返回值
        future01.runAfterBothAsync(future02,()->{
            System.out.println("任务3线程"+Thread.currentThread().getId());
        },executor);

        //任务1与任务2均结束,则执行任务3,任务3可以任务1与任务2的执行结果,任务3没有返回值
        future01.thenAcceptBothAsync(future02,(f1,f2)->{
            System.out.println("任务3开始...之前的结果"+f1+f2);
        },executor);

        //任务1与任务2均结束,则执行任务3,任务3可以任务1与任务2的执行结果,任务3有返回值
        CompletableFuture<String> future07 = future01.thenCombineAsync(future02, (f1, f2) -> {
            System.out.println("任务3开始");
            return (f1.toString()  + f2);
        }, executor);
        System.out.println(future07.get());

        //任务1与任务2只要其中一个完成,则执行任务3,任务3获取不到任务1与任务2的执行结果,任务3没有返回值
        future01.runAfterEitherAsync(future02,()->{
            System.out.println("任务3执行");
        },executor);

        //任务1与任务2只要其中一个完成,则执行任务3,任务3可以获取执行成功线程的执行结果,任务3没有返回值
        future01.acceptEitherAsync(future02,(f1)->{
            System.out.println("任务3执行,执行结果:"+f1);
        },executor);

        //任务1与任务2只要其中一个完成,则执行任务3,任务3可以获取执行成功线程的执行结果,任务3有返回值
        CompletableFuture<Integer> future06 = future01.applyToEitherAsync(future02, (f1) -> {
            System.out.println("任务3执行" + Thread.currentThread().getId());
            return (int) f1 + 100;
        }, executor);
        System.out.println(future06.get());

 allof:等待所有任务完成

anyof:只要有一个任务完成

  public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
        return andTree(cfs, 0, cfs.length - 1);
    }
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
        return orTree(cfs, 0, cfs.length - 1);
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值