6/11打卡 异步、线程池

1、异步

即把复杂的任务交付给其他的线程。因为当一个任务执行时间过长时,用户会长时间等待响应,导致体验下降,此时可以使用异步,让用户可以浏览其他内容或者说再提交其他图片任务。

2、线程

​ 线程管理十分麻烦,新增线程、减少线程、闲置线程、接受任务、拒绝任务、保证不抢到同一任务。

​ 当任务来临时,线程们如何不抢占同一个任务?(1、用的线程安全队列,任务只能被一个线程取出 2、每个线程执行任务时加锁,防止并发修改)

因此,我们之间直接线程池,yupi推荐使用JUC并发包中的线程池,一键配置线程

先写配置

java
复制代码
// config/ThreadPoolExecutorConfig package com.zxw.bi_intelligence.config; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.*; @Configuration public class ThreadPoolExecutorConfig { // 创建一个JUC线程池 @Bean public ThreadPoolExecutor threadPoolExecutor(){ // 初始化所有参数 // 核心线程数 int corePoolSize = 2; // 最大线程数 int maximumPoolSize = 4; // 线程空闲时间 long keepAliveTime =60L; // 时间单位 TimeUnit unit=TimeUnit.SECONDS; // 阻塞队列 // LinkedBlockingQueue 链表(Node 节点) 若不配置参数、则默认为Integer.MAX_VALUE // ArrayBlockingQueue 数组 必须指定队列大小 BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(4); // 线程工厂 ThreadFactory threadFactory = new ThreadFactory() { private int count=1; @Override // 每当线程池需要创建新线程时,就会调用newThread方法 // @NotNull Runnable r 表示方法参数 r 应该永远不为null, // 如果这个方法被调用的时候传递了一个null参数,就会报错 public Thread newThread(@NotNull Runnable r) { // 创建一个新的线程 Thread thread = new Thread(r); // 给新线程设置一个名称,名称中包含线程数的当前值 thread.setName("线程" + count + "号"); // 线程数递增 count++; // 返回新创建的线程 return thread; } }; /** * 拒绝策略:当线程池和队列都饱和时的处理方式 * CallerRunsPolicy:由调用线程(提交任务的线程)直接执行该任务 * 其他可选策略: * - AbortPolicy(默认):直接抛出RejectedExecutionException * - DiscardPolicy:静默丢弃无法处理的任务 * - DiscardOldestPolicy:丢弃队列中最旧的任务,然后重试执行 */ RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy(); return new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue ,threadFactory,rejectedExecutionHandler); } }

具体使用(测试)

java
复制代码
// 加载线程池配置 @Resource private ThreadPoolExecutor threadPoolExecutor; @GetMapping("/testAdd") public BaseResponse<String> addThreadTask(String name){ CompletableFuture.runAsync(()->{ // 打印一条日志信息,包括任务名称和执行线程的名称 log.info("任务执行中:" + name + ",执行人:" + Thread.currentThread().getName()); try { // 让线程休眠10分钟,模拟长时间运行的任务 Thread.sleep(600000); } catch (InterruptedException e) { e.printStackTrace(); } // 异步任务在threadPoolExecutor中执行 },threadPoolExecutor); return ResultUtils.success("successd"); } @GetMapping("/testQuery") public BaseResponse<String> queryThreadTask(){ Map<String,Object> map = new HashMap<>(); // 获取线程池的队列长度 int size = threadPoolExecutor.getQueue().size(); // 将队列长度放入map中 map.put("队列长度", size); // 获取线程池已接收的任务总数 long taskCount = threadPoolExecutor.getTaskCount(); // 将任务总数放入map中 map.put("任务总数", taskCount); // 获取线程池已完成的任务数 long completedTaskCount = threadPoolExecutor.getCompletedTaskCount(); // 将已完成的任务数放入map中 map.put("已完成任务数", completedTaskCount); // 获取线程池中正在执行任务的线程数 int activeCount = threadPoolExecutor.getActiveCount(); // 将正在工作的线程数放入map中 map.put("正在工作的线程数", activeCount); // 将map转换为JSON字符串并返回 return ResultUtils.success(JSONUtil.toJsonStr(map)); }

关键参数:corePoolSize、maximumPoolSize、队列长度

​ 我们可以将任务分类为I/O密集型(吃带宽/内存/硬盘的读写资源)和计算密集型(吃 CPU

I/O密集型:corePoolSize可以设置为2n

计算密集型:corePoolSize可以设置为n+1(设置过大则操作系统频繁通过时间片轮转算法进行线程调度,频繁的切换上下文,严重影响性能,可能切换的消耗比执行时间都长)

​ 设置的数值还需要根据服务器的性能,执行时的情况动态进行调整

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
鱼友4537
下载 APP