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

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

相关推荐
Rick19933 小时前
Java内存参数解析
java·开发语言·jvm
我是大猴子3 小时前
Spring代理类为何依赖注入失效?
java·后端·spring
勿忘,瞬间3 小时前
多线程之进阶修炼
java·开发语言
014-code3 小时前
线程池参数怎么配才不翻车
java
吴梓穆3 小时前
UE5 c++ 常用方法
java·c++·ue5
hoiii1874 小时前
CSTR反应器模型的Simulink-PID仿真(MATLAB实现)
开发语言·matlab
王夏奇4 小时前
python中的__all__ 具体用法
java·前端·python
明湖起风了4 小时前
mqtt消费堆积
java·jvm·windows
Free Tester4 小时前
如何判断 LeakCanary 报告的严重程度
java·jvm·算法
炘爚4 小时前
C++ 右值引用与程序优化
开发语言·c++