线程池知识点汇总

1. Java 中的线程池是如何实现的

在 Java 中, 所谓的线程池中的 "线程", 其实是被抽象为了一个静态内部类 Worker, 它基于 AQS 实现, 存放在线程池的 HashSet<Worker> workers 成员变量中;

需要执行的任务则存放在成员变量 workQueue (Blocking Queue <Runnable> workQueue) 中. 这样整个线程池实现的基本思想就是: 从 workQueue 中不断取出需要执行的任务, 放在 Workers 中进行处理. 

2. 创建线程池的几个核心构造参数有哪些

Java 中的线程池的创建其实非常灵活, 我们可以通过配置不同的参数, 创建出行为不同的线程池, 这几个参数包括: 

corePoolSize: 线程池的核心线程数.

maximumPoolSize: 线程池运行的最大线程数.

keepAliveTime: 超过核心线程数时闲置线程的存活时间

workQueue: 任务执行前保存任务的队列, 保存由 execute 方法提交的 Runnable 任务.

3. 线程池中的线程怎么创建的? 是一开始就随着线程池的启动创建的嘛

不是, 线程池默认初始化不启动 Worker, 等待有请求时才启动.

每当我们调用 execute() 方法添加一个任务时, 线程池会做如下判断:

  • 如果正在运行的线程数量小于 corePoolSize , 那么马上创建线程运行这个任务
  • 如果这个任务的线程数量大于或等于 corePoolSize, 那么将这个任务放入队列
  • 如果队列满了, 而且正在运行的线程数量小于 maximumPoolSize, 那么还是要创建非核心线程立刻运行这个任务
  • 如果队列满了, 而且正在运行的线程数量大与或等于 maximumPoolSize, 那么线程池就会抛出异常 RejectExecutionException.

当一个线程完成任务时, 它会从队列中取出下一个任务来执行. 当线程数量大于 corePoolSize , 如果有线程的闲置时间超过 keepAliveTime 时, 这个线程就会被释放掉.

4. 既然提到可以通过配置不同参数创建出不同的线程池, 那么 Java 中默认实现好的线程池又有哪些? 比较他们的异同

SingleThreadExecutor 线程池

这个线程池只有一个核心线程在工作, 也就是相当于单线程串行执行所有任务. 如果这个唯一的线程因为异常结束, 那么会有一个新的线程来代替它. 此线程池保证所有任务的执行顺序按照任务的提交顺序执行.

  • corePoolSize: 1
  • maximumPoolSize: 1
  • keepAliveTime: 0
  • workQueue: new LinkedBlockingQueue <Runnable> (), 其缓冲队列是无界的.

FixedThreadPool 线程池

FixedThreadPool 是固定大小的线程池, 只有核心线程. 每次提交一个任务就会创建一个线程, 知道线程达到线程池的最大大小. 线程池的大小一旦达到最大值就会保持不变, 如果某个线程因为执行异常而结束, 那么线程池会补充一个新的线程池

FixedThreadPool 多数针对一些很稳定, 固定的正规并发线程, 多用于服务器

  • corePoolSize: n
  • maximumPoolSize: n
  • keepAliveTime: 0
  • workQueue: new LinkedBlockingQueue <Runnable> (), 其缓冲队列是无界的

CachedThreadPool 线程池

CachedThreadPool 是无界线程池, 如果线程池的大小超过了处理任务锁需要的线程, 那么就会回收部分空闲(60s 不执行任务) 的线程, 当任务数增加时, 此线程池又会添加新线程来处理任务.

线程池大小完全依赖于操作系统(或者说 JVM) 能够创建的最大线程数大小. workQueue 为 SynchronousQueue, 是一个缓冲区为 1 的阻塞队列.

缓存型池子通常用于执行一些生存周期很短的异步型任务.

  • corePoolSize: 0
  • maximumPoolSize: Integer.Max_Value
  • KeepAliveTime: 60s
  • workQueue: new SynchronousQueue<Runnable>(), 一个缓冲区为1的阻塞队列

ScheduledThreadPool 线程池

ScheduledThreadPool 核心线程池固定, 大小无限的线程池. 此线程池支持定时以及周期性执行任务的需求. 创建一个周期性执行任务的线程池. 如果闲置, 非核心线程池会在 DEFAULT_KEEPALIVEMILLIS 时间内回收

  • corePoolSize: 0;
  • maximumPoolSize: Integer.MAX_VALUE
  • keepAliveTime: DEFAULT_KEEPALIVE_MILLIS
  • workQueue: new DelayedWorkQueue()

5. 如何在 Java 线程池中提交线程

线程池最常用的提交任务的方法有两种:

  • execute(): ExecutorService.execute 方法接收一个 Runnable 实例, 它用来执行一个任务
  • submit(): ExecutorService.submit() 方法返回的是 Future 对象. 可以用 isDone() 来查询 Future 是否已经完成, 当任务完成时, 它具有一个结果, 可以调用 get() 来获取结果. 也可以不用 isDone() 进行检查就直接调用 get(), 这种情况下, get() 将阻塞, 直至结果准备就绪.

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值