你有没有遇到过这种情况:电脑同时打开十几个网页,突然卡住不动?或者后台运行几个程序时,整个系统变得特别慢。其实问题可能出在“线程”管理上。每个任务都开一个新线程,资源很快就被耗尽了。为了解决这个问题,程序员们想了个聪明的办法——用线程池。
什么是线程池?
你可以把线程池想象成一家快递站点。每天有大量包裹要送,如果每来一个包裹就招一个快递员,成本高还管理混乱。更合理的做法是保持一支固定队伍,包裹来了就分给空闲的人。线程池干的就是这个事:提前创建一批线程,任务来了就交给空闲线程处理,用完不扔,回头继续用。
线程池的核心结构
一个典型的线程池包含几个关键部分:线程集合、任务队列、调度机制。线程一开始就在池子里待命,任务被提交后先进入队列排队。一旦有线程空出来,立刻从队列取新任务执行。
比如 Java 中常见的 ThreadPoolExecutor,它允许你设定核心线程数、最大线程数、空闲存活时间以及任务等待队列。这样既能应对突发负载,又不会无限制创建线程拖垮系统。
工作流程是怎么样的?
当新任务提交进来,线程池先检查有没有空闲线程。如果有,直接分配;如果没有,看当前线程数量是否达到核心线程数,没达到就新建一个。如果核心线程都忙,任务就会进队列等。队列也满的话,再看能不能扩容到最大线程数。超过这个极限,就触发拒绝策略——比如直接丢弃或抛异常。
代码长什么样?
ExecutorService pool = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
pool.submit(() -> {
System.out.println("任务正在执行,线程名:" + Thread.currentThread().getName());
});
}
pool.shutdown();
这段代码创建了一个固定大小为5的线程池,提交10个任务。你会发现只有5个线程在轮流干活,而不是生成10个新线程。
为什么要复用线程?
每次新建线程都要操作系统分配资源,包括栈内存、ID 等,这个过程叫“上下文切换”,挺耗时间的。就像每次送快递都要重新培训一个人,效率当然低。而复用已有线程,省去了初始化开销,响应更快,系统也更稳定。
不同类型的线程池
除了固定大小的线程池,还有可缓存的(CachedThreadPool),适合短时间大量异步任务;有定时调度的(ScheduledThreadPool),像闹钟一样定期执行;还有单线程的,保证任务按顺序执行。选哪种取决于你的使用场景。
别忘了设置拒绝策略
现实世界中,订单太多快递站爆仓怎么办?得有个预案。线程池也一样。可以设置当任务队列满了之后,是让调用者自己处理(CallerRunsPolicy),还是直接抛异常(AbortPolicy),甚至丢弃最老的任务(DiscardOldestPolicy)。合理配置能避免系统雪崩。
小改动,大效果
很多 Web 服务器默认就用了线程池处理用户请求。比如你访问一个网站,服务器不会为每个访问者新开线程,而是由线程池统一调度。这样即使同时来几千人,系统也能扛得住。这种设计看似不起眼,却是高性能服务的基石之一。