Java线程池学习

众所周知,Java不仅提供了线程,也提供了线程池库给我们使用,那么今天来学学线程池的具体使用以及线程池基本实现原理分析。


ThreadPoolExecutor

ThreadPoolExecutor的构造方法:

public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}

参数解释如下:

  • corePoolSize : 核心池大小,即线程的数量
  • maximumPoolSize : 线程池最大数量
  • keepAliveTime : 线程池中的线程的保活时间,超时后线程会退出直到线程池中的线程数量等于corePoolSize,如果allowCoreThreadTimeout为true,线程数量会降为0
  • workQueue:线程池采用的缓冲队列,常用的有:java.util.concurrent.ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue
  • handler:当线程池中线程数量达到maximumPoolSize时,仍有任务需要创建线程来完成,则handler采取相应的策略,默认的ThreadPoolExecutor.AbortPolicy(),即会抛弃该任务。

线程池中可能的几种状态:

  • 当线程数量小于corePoolSize时,任务来时会创建新的线程来处理,并把该线程加入线程队列中(实际上是一个hashset)(此步骤需要获取全局锁,ReentryLock)

  • 如果当前线程数量达到了corePoolSize,任务来时将任务加入BlockingQueue

  • 如果任务列队满了无法加入新的任务时,会创建新的线程(同样需要获取全局锁)

  • 如果线程池数量达到maximumPoolSize,并且任务队列已满,新的任务将被拒绝

注意:获取全局锁是一个非常影响性能的因素,所以线程池会尽量执行第二步,因为此步骤不需要获取全局锁。

各种任务队列(BlockingQueue)的区别

  • ArrayBlockingQueue: 基于数组的有界阻塞队列,FIFO

  • LinkedBlockingQueue:基于链表的无界阻塞队列,FIFO,吞吐量高于ArrayBlockingQueue,Executors.newFixedThreadPool()使用了该队列

  • SynchronousQueue:一个不存储元素的队列,一进一出吞吐量高于LinkedBlockingQueue,Executors.newCachedThreadPool()使用了该队列

  • PriorityBlockingQueue:阻塞优先队列

RejectedExecutionHandler饱和拒绝策略

  • AbortPolicy:直接抛出异常
  • CallerRunsPolicy:只用调用者所在线程来运行任务
  • DiscardOldestPolicy:丢弃队列里最近的任务,并执行当前任务
  • DiscardPolicy:不处理,不丢弃

提交一个任务

两种方式:

threadPool.submit(new Runnable() {
@Override
public void run() {
//
}
});

上面是第一种,通过submit方法提交,该方法有返回值,返回类型是Future<?>类型,

threadPool.execute(new Runnable() {
@Override
public void run() {
//
}
});

上面是第二种,通过execute执行,无返回值。

关闭线程池

shutdown()和showdownNow()两种方法,都是调用了interruptIdleWorkers()方法去遍历线程池中的工作线程,然后去打断它们,代码如下:

private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
//中断线程
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}

不同的是shutdown是把线程的状态置为SHUTDOWN而shutdownNow是STOP。

调优

  • 尽量使用有界队列
  • 线程池中的线程数量应该根据场景来合理配置,例如CPU密集型的任务就应该配置尽量少的线程数量

Executors工具类

主要介绍工具类Executors创建的三种线程池:

ExecutorService executorService = Executors.newSingleThreadExecutor();
ExecutorService executorService1 = Executors.newFixedThreadPool(10);
ExecutorService executorService2 = Executors.newCachedThreadPool();

FixedThreadPool

源码如下:

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}

可以看出core和max数量是一样的,因为使用的LinkedBlockingQueue是无界阻塞队列,因此达到coreSize后不会继续创建线程而是阻塞在队列那了。

SingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}

只创建一个线程的线程池。

CachedThreadPool

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

使用了SynchronousQueue这个没有容量的阻塞队列,线程池的coreSize为0,maxSize为无限大,所以当生产者提供任务的速度大于消费者处理任务的时候,可能会无线创建线程,从而导致系统资源(CPU,内存等)耗竭。

【Java多线程】线程池学习的更多相关文章

  1. [Java多线程]-线程池的基本使用和部分源码解析(创建,执行原理)

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 多线 ...

  2. 跟我学Java多线程——线程池与堵塞队列

    前言 上一篇文章中我们将ThreadPoolExecutor进行了深入的学习和介绍,实际上我们在项目中应用的时候非常少有直接应用ThreadPoolExecutor来创建线程池的.在jdk的api中有 ...

  3. java多线程--线程池的使用

    程序启动一个新线程的成本是很高的,因为涉及到要和操作系统进行交互,而使用线程池可以很好的提高性能,尤其是程序中当需要创建大量生存期很短的线程时,应该优先考虑使用线程池. 线程池的每一个线程执行完毕后, ...

  4. java多线程-线程池

    线程池(Thread Pool)对于限制应用程序中同一时刻运行的线程数很有用.因为每启动一个新线程都会有相应的性能开销,每个线程都需要给栈分配一些内存等等. 我们可以把并发执行的任务传递给一个线程池, ...

  5. Java多线程——线程池

    系统启动一个新线程的成本是比较高的,因为它涉及到与操作系统的交互.在这种情况下,使用线程池可以很好的提供性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池. 与数据库连接池类似 ...

  6. java多线程——线程池源码分析(一)

    本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 通常应用多线程技术时,我们并不会直接创建一个线程,因为系统启动一个新线程的成本是比较高的,涉及与操作系统的交互, ...

  7. java多线程----线程池源码分析

    http://www.cnblogs.com/skywang12345/p/3509954.html 线程池示例 在分析线程池之前,先看一个简单的线程池示例. 1 import java.util.c ...

  8. 深入理解Java多线程——线程池

    目录 为什么需要线程池 定义 ThreadPoolExecutor 工作队列workQueue 不同的线程池 Executor 线程池的工作原理 线程池生命周期 线程池增长策略 线程池大小的设置 线程 ...

  9. Java多线程-线程池ThreadPoolExecutor构造方法和规则

    为什么用线程池 原文地址 http://blog.csdn.net/qq_25806863/article/details/71126867 有时候,系统需要处理非常多的执行时间很短的请求,如果每一个 ...

  10. Java多线程-----线程池详解

    1. 线程池的实现原理 提交一个任务到线程池中,线程池的处理流程如下: 判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务.如果 ...

随机推荐

  1. spring mvc 注解详解

    1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ...

  2. 【BZOJ1093】【ZJOI2007】最大半联通子图 [DP][Tarjan]

    最大半连通子图 Time Limit: 30 Sec  Memory Limit: 162 MB[Submit][Status][Discuss] Description 一个有向图G=(V,E)称为 ...

  3. 基本控件文档-UISegment属性----iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ...

  4. 将四个按钮放入一个父控件的好处:方便移动,只需要改变父控件的y值,就可移动四个按钮

      将四个按钮放入一个父控件的好处:方便移动,只需要改变父控件的y值, 就可移动四个按钮               https://www.evernote.com/shard/s227/sh/78 ...

  5. Lua中调用C++方法

    目前项目,使用了Lua脚本,至于使用Lua的好处不再赘述了.于是对Tolua做了一些小小的学习,总结一下吧. 主要说一下如何在Lua中调用C++方法. Lua调用C++的桥梁,是tolua.tolua ...

  6. php中比较好用的函数

    PHP中一个好用的函数parse_url,特别方便用来做信息抓取的分析,举例子如下: $url = "http://www.electrictoolbox.com/php-extract-d ...

  7. windows10安装oracle11g报错ORA-01034、ORA-01078

    ORA-01034表示数据库实例未建立,可以先用管理员账号进入一个空白实例 sqlplus / as sysdba; 如果您当前使用的账号是安装oracle的账号,则不需要账号密码就可以登陆oracl ...

  8. nodejs安装express以后,使用express显示不是内部或外部命令

    1.问题描述 在命令窗口通过npm install -g express 安装express以后,通过express -e express新建工程失败,提示express不是内部或外部命令 2.解决方 ...

  9. 自己动手一步步安装Linux系统

    自己动手一步步安装Linux系统 http://502245466.blog.51cto.com/7559397/1291910/

  10. pxc群集搭建

    pxc群集搭建 1.环境 Percona-XtraDB 5.7.22-22-29.26-log percona-xtrabackup-24-2.4.12 192.168.99.210:3101(第一节 ...