线程池是Java开发中常用的功能,在日常开发经常用到,那对于其的实现原理是否了解?下面就线程池的原理做个简单的分析。就从最简单的使用开始来分析具体实现和领悟JDK 实现的基本思想。
- 最简单的线程池使用方式
ExecutorService service = Executors.newFixedThreadPool(10); service.execute(new Runnable() { @Override public void run() { System.out.println("executor"); } });
上面是最简单的线程池使用方式,那线程池是如何运行该提交的执行任务的呢?下来分两步来分析:
- 线程池的初始化,下面是Executors类里面的初始化线程池的方法:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
根据上面newFixedThreadPool方法来看,只是返回了一个ThreadPoolExecutor对象,注意的是整个JDK实现的线程池关键的一个类就是ThreadPoolExecutor,包括调度线程池最终也是初始化的ThreadPoolExecutor对象。那我们来看看ThreadPoolExecutor这个关键的类的构造方法都做了什么事情:
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.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
由上面的构造方法来看,先是对关键参数做了检查,满足条件之后实际就是将客户端传入的参数或者相关默认参数初始化成ThreadPoolExecutor对象返回给客户端。
初始化一个线程池有几项比较关键的参数
属性 | 含义 |
corePoolSize | 线程池的最小大小,也就是初始化大小。 |
maximumPoolSize | 线程池的最大大小,对于当前线程池处理的任务超过此数目,则任务只能等待有其他工作线程释放之后才能继续处理新的提交任务。 |
workQueue |
工作队列,当客户端向线程池提交的任务数量大于核心线程池大小时会先存入此队列中。 如果客户端向线程池提交的任务数量小于核心数量,则不会向队列中添加,而是直接启动一个新的线程执行提交的任务。 |
threadFactory | 线程工厂。顾名思义就是创建线程的工厂对象,使用者可以自定义自己的线程工厂,不指定则使用JDK默认的线程工厂。第二步,提交工作线程 |
第二步,提交工作线程
service.execute(new Runnable() { @Override public void run() { System.out.println("executor"); } });
执行上述代码为什么会执行run()方法呢?下面来分析下server.execute()方法。
- 比较当前工作的worker线程是否小于核心/最小线程池大小,这里是我们代码中指定的10,如果小于则添加到Worker线程池工作任务数组中,并直接诶开启新的线程执行任务。
-
如果提交的任务数量大于核心线程池大小,这个时候工作队列就派上用处了,会把提交的任务提交的工作队列中,等待空闲线程去工作队列中去任务执行。
-
如果加入工作队列失败,则尝试添加到Worker线程组中,并启动新的线程执行任务。如果当前线程超过了最大线程池大小,则会拒绝此任务的执行,任务执行失败。
总体来看,java线程池的实现很大一部分就是依赖的工作阻塞队列(BlockingQueue),默认的工作队列有
LinkedBlockingQueue SynchronousQueue 等多种。线程池能够做到线程的高度复用实际也是依赖阻塞队列优秀的阻塞、唤醒机制。
下面我们来分析阻塞队列的实现机制。
相关推荐
}关于FutureTask这个类的实现,我在前面的JAVA LOCK代码浅析有讲过其实现原理,主要的思想就是关注任务完成与未完成的状态,任务提交线程get()结
java 虚拟机原理浅析,希望大家来交流
本文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细 致的研 究。如果下面的内容有错误或不严谨的地方,也请指正和谅解。对于Netty使用者来说,Netty提供了几个典型的example,并有详尽的...
声音技术浅析.doc
Netty实现原理浅析
java组件的浅析
Java内存分析
java 中文乱码浅析及解决方案
Struts1工作原理浅析
流行java技术架构浅析借鉴.pdf
java数据类型浅析.ppt
深入Java单例模式浅析,最全面的深入解析
高校Java课程教学浅析
JAVA Socket超时浅析 转
GSM蜂窝基站定位基本原理浅析[参照].pdf
NULL 博文链接:https://278672937.iteye.com/blog/2146869
受电弓系统工作原理浅析.docx受电弓系统工作原理浅析.docx受电弓系统工作原理浅析.docx受电弓系统工作原理浅析.docx受电弓系统工作原理浅析.docx受电弓系统工作原理浅析.docx受电弓系统工作原理浅析.docx受电弓系统...
流媒体客户端的结构与原理浅析流媒体客户端的结构与原理浅析
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。...