从Java线程池的常用4种写法深入分析线程池的实现原理

本文详细介绍了Java中的线程池,包括FixedThreadPool、SingleThreadExecutor、CachedThreadPool和ScheduledThreadPool四种常见类型,通过示例展示了它们的工作原理。线程池通过预先创建线程来减少资源消耗,其核心参数包括核心线程数、最大线程数、存活时间等,以及线程池的执行流程、拒绝策略和面试中常问的问题。
摘要由CSDN通过智能技术生成

什么是线程池

在Java中,创建一个线程可以通过继承Thread或者实现Runnable接口来实现,但是,如果每个请求都创建一个新线程,那么创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。

为了解决这个问题,就有了线程池的概念,线程池的核心逻辑是提前创建好若干个线程放在一个容器种。如果有任务需要处理,则将任务直接分配给线程池中的线程来执行就行,任务处理完以后这个线程不会被销毁,而是等待后续分配任务。同时通过线程池来重复管理线程还可以避免创建大量线程增加开销。

创建线程池

为了方便使用,Java中的Executors类里面提供了几个线程池的工厂方法,可以直接利用提供的方法创建不同类型的线程池:

  • newFixedThreadPool:创建一个固定线程数的线程池
  • newSingleThreadExecutor:创建只有1个线程的线程池
  • newCachedThreadPool:返回一个可根据实际情况调整线程个数的线程池,不限制最大线程 数量,若用空闲的线程则执行任务,若无任务则不创建线程。并且每一个空闲线程会在60秒 后自动回收。
  • newScheduledThreadPool: 创建一个可以指定线程的数量的线程池,但是这个线程池还带有 延迟和周期性执行任务的功能,类似定时器。

FixedThreadPool

创建一个固定数量N个线程在一个共享的无边界队列上操作的线程池。在任何时候,最多N个线程被激活处理任务。如果所有线程都在活动状态时又有新的任务被提交,那么新提交的任务会加入队列等待直到有线程可用为止。

如果有任何线程在shutdown前因为失败而被终止,那么当有新的任务需要执行时会产生一个新的线程,新的线程将会一直存在线程池中,直到被显示的shutdown。

示例

package com.zwx.concurrent.threadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
​public class TestThreadPool {
    public static void main(String[] args) {
        //FixedThreadPool - 固定线程数
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i=0;i<10;i++){
            fixedThreadPool.execute(()-> {
                System.out.println("线程名:" + Thread.currentThread().getName());
            });
        }
        fixedThreadPool.shutdown();
    }
}

输出结果为:

从Java线程池的常用4种写法深入分析线程池的实现原理

 

可以看到,最多只有3个线程在循环执行任务(运行结果是不一定的,但是最多只会有3个线程)。

FixedThreadPool调用了如下方法构造线程池:

从Java线程池的常用4种写法深入分析线程池的实现原理

 

SingleThreadExecutor

只有一个工作线程的执行器。如果这个线程在正常关闭前因为执行失败而被关闭,那么就会重新创建一个新的线程加入执行器。

这种执行器可以保证所有的任务按顺序执行,并且在任何给定的时间内,确保活动的任务只有1个。

示例

package com.zwx.concurrent.threadPool;
​import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
​public class TestThreadPool {
    public static void main(String[] args) {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();        for (int i=0;i<9;i++){
            singleThreadExecutor.execute(()-> {                System.out.println("线程名:" + Thread.currentThread().getName());
            });        }    }}singleThreadExecutor.shutdown();

运行结果只有1个线程:

从Java线程池的常用4种写法深入分析线程池的实现原理

 

SingleThreadExecutor调用了如下方法构造线程池:

从Java线程池的常用4种写法深入分析线程池的实现原理

 

CachedThreadPool

一个在需要处理任务时才会创建线程的线程池,如果一个线程处理完任务了还没有被回收,那么线程可以被重复使用。

当我们调用execute方法时,如果之前创建的线程有空闲可用的,则会复用之前创建好的线程,否则就会创建新的线程加入到线程池中。

创建好的线程如果在60s内没被使用,那么线程就会被终止并移出缓存。因此,这种线程池可以保持长时间空闲状态而不会消耗任何资源。

示例

package com.zwx.concurrent.threadPool;
​import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
​​public class TestThreadPool {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();        for (int i=0;i<9;i++){
            cachedThreadPool.execute(()-> {                System.out.println("线程名:" + Thread.currentThread().getName());
            });        }        cachedThreadPool.shutdown();}

输出结果可以看到,创建了9个不同的线程:

从Java线程池的常用4种写法深入分析线程池的实现原理

 

接下来我们对上面的示例改造一下,在执行execute之前休眠一段时间:

package com.zwx.concurrent.thre
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值