Java-线程池(八股)

创建方法:Java原生创建线程池与Spring创建线程池

Java原生创建线程池:

一、手动创建ThreadPollExecutor

java 复制代码
// Java原生线程池核心构造方法
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
    int corePoolSize,        // 核心参数1:核心线程数(常驻线程数)
    int maximumPoolSize,     // 核心参数2:最大线程数(线程池能创建的最大线程数)
    long keepAliveTime,      // 核心参数3:空闲线程存活时间
    TimeUnit unit,           // 核心参数4:存活时间的单位(秒/毫秒等)
    BlockingQueue<Runnable> workQueue,  // 核心参数5:任务阻塞队列(核心线程满了放这里)
    ThreadFactory threadFactory,        // 核心参数6:线程工厂(自定义线程名称、优先级等)
    RejectedExecutionHandler handler     // 核心参数7:拒绝策略(队列满+线程满时的处理方式)
);

二、Spring创建线程池

核心类是ThreadPoolTaskExecutor。

纯注解方式(@Configuration+@Bean,SpringBoot首选)

代码示例:

步骤一:编写线程类的核心配置类:
java 复制代码
@Configuration
public class SpringThreadPoolConfig {
    @Bean("customThreadPool")
    public Executor customThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(30);
        executor.setThreadNamePrefix("SPRING-THREAD-POOL-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化线程池(必须调用,否则线程池不生效)
        executor.initialize();
        return executor;
    }
}
步骤二:业务代码中注入并使用线程池
java 复制代码
@Service
public class ThreadPoolService {

    // 注入线程池:@Qualifier指定Bean的名称,避免多个线程池时注入失败
    @Autowired
    @Qualifier("customThreadPool")
    private Executor customThreadPool;

    // 业务方法中执行异步任务
    public void doAsyncTask() {
        for (int i = 1; i <= 5; i++) {
            int finalI = i;
            customThreadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " 执行异步任务:" + finalI);
                try { Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace();}
            });
        }
    }
}

三、Spring线程池(@Async异步注解)

步骤1:在配置类上添加@EnbaleAsync注解(开启异步支持)
java 复制代码
@Configuration
@EnableAsync
public class SpringThreadPoolConfig {
    @Bean("customThreadPool")
    public Executor customThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(30);
        executor.setThreadNamePrefix("SPRING-THREAD-POOL-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}
步骤2:在业务方法上添加@Async(线程池Bean名)注解
java 复制代码
@Service
public class AsyncTaskService {

    /**
     * 被@Async注解的方法,会被自动提交到指定的线程池异步执行
     * 无需手动调用线程池,Spring自动处理,无感知!
     */
    @Async("customThreadPool")
    public void doAsyncTask(int taskId) {
        System.out.println(Thread.currentThread().getName() + " 执行异步任务:" + taskId);
        try { Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace();}
    }
}
步骤3:调用该方法即可(同步调用,异步执行)
java 复制代码
@Controller
public class TaskController {
    @Autowired
    private AsyncTaskService asyncTaskService;

    @GetMapping("/task")
    public String doTask() {
        for (int i = 1; i <= 5; i++) {
            // 同步调用,但方法内部会异步执行
            asyncTaskService.doAsyncTask(i);
        }
        return "success";
    }
}

线程池的种类:

1、newCachedThreadPool

创建一个可缓存线程池,如果当前线程池的长度超过了处理的需要时,它可以灵活的回收空闲的线程。当需要增加的时候,可以灵活的添加新的线程,不会对线程的长度做出任何限制。

2、newFixedThreadPool

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

3、newScheduledThreadPool

创建一个固定长度的线程池,支持定时的以及周期性的任务执行

4、newSingleThreadExecutor

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来代替它,它保证前一项任务执行完毕后才执行后一项。保证所有任务按照指定顺序执行。

线程池的拒绝策略:

AbortPolicy,默认

线程池的默认拒绝策略,如果线程池满了丢掉这个任务并且抛出RejectedExecutionExcepitio异常

DiscardPolicy

是AbortPolicy的silent版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常。

DiscardOldestPolicy

丢弃最老的。如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列。

CallerRunsPolicy

如果添加到线程池失败,那么调用线程会自己去执行该任务,不会等待线程池中的线程去执行。

相关推荐
桦说编程2 小时前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
躺平大鹅4 小时前
Java面向对象入门(类与对象,新手秒懂)
java
初次攀爬者5 小时前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺5 小时前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart6 小时前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP7 小时前
MyBatis-mybatis入门与增删改查
java
孟陬11 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌11 小时前
一站式了解四种限流算法
java·后端·go
华仔啊11 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java