我是靠谱客的博主 时尚橘子,这篇文章主要介绍java多线程线程池原理剖析Java线程池,现在分享给大家,希望可以做个参考。

文章目录

  • Java线程池
    • 线程复用
    • 线程池概念
    • 线程池工作原理
    • ThreadPoolExecutor原理
      • 源码原理
        • 拒绝策略
        • 任务阻塞队列
      • 如何实现线程复用
    • newCachedThreadPool

Java线程池

线程复用

线程的创建和销毁,都是重量级工作,非常的消耗性能,高并发或者频繁的线程使用场景下对机器的要求很高,会造成性能瓶颈

可以使用线程池优化线程的频繁使用场景,使线程达到重复使用而不销毁,原理类似数据库连接池,http连接池等…

线程池概念

在线程池中,当你需要使用线程时,可以从池子中随便拿一个空闲线程,当完成工作时,并不急着关闭线程,而是将这个线程退回到线程池中

相当于创建线程变成了从线程池中获取线程
关闭线程变成了将线程退回给线程池

线程池工作原理

线程池定义:

  1. 核心线程数
  2. 最大线程数
  3. 保持空闲最大时长
  4. 工作队列
  5. 拒绝策略

image-20210509233849851

  1. 线程池中原本没有线程,当任务队列中有任务的时候,才通过线程工厂创建线程,创建好的线程在线程池中为空闲状态,空闲状态的线程会以自旋的方式不断的从任务队列中取出任务执行,如果线程正在执行任务中,则为活跃状态,任务执行结束后又会回到空闲状态
  2. 线程工厂不会一直创建线程,当线程达到了线程池的最大线程数时就不会再创建线程
  3. 创建出来的线程不会一直存在于线程池中,如果线程池中的线程数量 > 核心线程数,则线程池会销毁处于空闲状态并持续了[保持空闲最大时长]的线程
  4. 任务队列中的一个任务被线程获取执行了则会从队列中移除
  5. 如果线程池中的所有线程都处于活跃中,则来不及处理的任务就会被堆积在任务队列中
  6. 当任务队列无法再存储更多任务的时候,这些无法存储的任务就会执行拒绝策略

ThreadPoolExecutor原理

源码原理

ThreadPoolExecutor构造器

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/** * 创建一个线程池 * * @param corePoolSize 核心线程数 * @param maximumPoolSize 最大线程数 * @param keepAliveTime 保持空闲最大时长 * @param unit 时间单位 * @param workQueue 工作队列,阻塞队列 * @param threadFactory 线程工厂 * @param handler 拒绝执行的策略 */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }

常见的实现

image-20210509235440042

拒绝策略

image-20210509235523834

任务阻塞队列

image-20210509235558301

如何实现线程复用

如何实现Runable被执行完成后线程不会结束

答案是ThreadPoolExecutor.Worker

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class ThreadPoolExecutor extends AbstractExecutorService { // ...忽略其他代码 private final class Worker extends AbstractQueuedSynchronizer implements Runnable { // ...忽略其他代码 /** Thread this worker is running in. Null if factory fails. */ final Thread thread; /** Initial task to run. Possibly null. */ Runnable firstTask; Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this); } public void run() { runWorker(this); } final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) { w.lock(); // If pool is stopping, ensure thread is interrupted; // if not, ensure thread is not interrupted. This // requires a recheck in second case to deal with // shutdownNow race while clearing interrupt if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { beforeExecute(wt, task); Throwable thrown = null; try { task.run(); } catch (RuntimeException x) { thrown = x; throw x; } catch (Error x) { thrown = x; throw x; } catch (Throwable x) { thrown = x; throw new Error(x); } finally { afterExecute(task, thrown); } } finally { task = null; w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } } } }

可以看到,实际线程池在创建线程的时候,线程中执行的Runnable并不是我们的Runnable任务
线程池自己实现了一个Runnable,用于绑定一个线程,并持续的在线程中自旋持续不断的从任务队列中获取出我们的Runnable并执行一次,这就是为什么线程在执行完我们的Runnable任务后,线程仍然存在并且没有关闭的原因,因为线程执行的实际上是WorkerWorker一直没有停止工作,是Woeker在执行我们的Runnable任务

newCachedThreadPool

复制代码
1
2
3
4
5
6
7
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }

缓存线程池newCachedThreadPool实际上并没有核心线程数,所以其实是将所有的线程都缓存60秒,就类似给Redis的key设置过期时间为60s一样,在线程空闲60秒后就会被销毁

最后

以上就是时尚橘子最近收集整理的关于java多线程线程池原理剖析Java线程池的全部内容,更多相关java多线程线程池原理剖析Java线程池内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(82)

评论列表共有 0 条评论

立即
投稿
返回
顶部