文章目录
- Java线程池
- 线程复用
- 线程池概念
- 线程池工作原理
- ThreadPoolExecutor原理
- 源码原理
- 拒绝策略
- 任务阻塞队列
- 如何实现线程复用
- newCachedThreadPool
Java线程池
线程复用
线程的创建和销毁,都是重量级工作,非常的消耗性能,高并发或者频繁的线程使用场景下对机器的要求很高,会造成性能瓶颈
可以使用线程池优化线程的频繁使用场景,使线程达到重复使用而不销毁,原理类似数据库连接池,http连接池等…
线程池概念
在线程池中,当你需要使用线程时,可以从池子中随便拿一个空闲线程,当完成工作时,并不急着关闭线程,而是将这个线程退回到线程池中
相当于创建线程变成了从线程池中获取线程
关闭线程变成了将线程退回给线程池
线程池工作原理
线程池定义:
- 核心线程数
- 最大线程数
- 保持空闲最大时长
- 工作队列
- 拒绝策略
- 线程池中原本没有线程,当任务队列中有任务的时候,才通过线程工厂创建线程,创建好的线程在线程池中为空闲状态,空闲状态的线程会以自旋的方式不断的从任务队列中取出任务执行,如果线程正在执行任务中,则为活跃状态,任务执行结束后又会回到空闲状态
- 线程工厂不会一直创建线程,当线程达到了线程池的最大线程数时就不会再创建线程
- 创建出来的线程不会一直存在于线程池中,如果线程池中的线程数量 > 核心线程数,则线程池会销毁处于空闲状态并持续了[保持空闲最大时长]的线程
- 任务队列中的一个任务被线程获取执行了则会从队列中移除
- 如果线程池中的所有线程都处于活跃中,则来不及处理的任务就会被堆积在任务队列中
- 当任务队列无法再存储更多任务的时候,这些无法存储的任务就会执行拒绝策略
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; }
常见的实现
拒绝策略
任务阻塞队列
如何实现线程复用
如何实现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
71public 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
任务后,线程仍然存在并且没有关闭的原因,因为线程执行的实际上是Worker
,Worker
一直没有停止工作,是Woeker
在执行我们的Runnable
任务
newCachedThreadPool
1
2
3
4
5
6
7public 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线程池内容请搜索靠谱客的其他文章。
发表评论 取消回复