Executors 类对 ThreadPoolExecutor 的构造函数进行了封装,使用该类可方便地创建线程池。

1. newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
} // 对应的ThreadPoolExecutor设置如下:
this.corePoolSize = nThreads;
this.maximumPoolSize = nThreads;
this.workQueue = new LinkedBlockingQueue<Runnable>();
this.keepAliveTime = TimeUnit.MILLISECONDS.toNanos(0L);
this.threadFactory = Executors.defaultThreadFactory();
this.handler = defaultHandler;

2. newCachedThreadPool

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
} // 对应的ThreadPoolExecutor设置如下:
this.corePoolSize = 0;
this.maximumPoolSize = Integer.MAX_VALUE;
this.workQueue = new SynchronousQueue<Runnable>();
this.keepAliveTime = TimeUnit.SECONDS.toNanos(60L); //60秒
this.threadFactory = Executors.defaultThreadFactory();
this.handler = defaultHandler;

分析任务入队和出队,分别对应 ThreadPoolExecutor 类的 execute 方法和 getTask 方法:

public void execute(Runnable command) {
if (command == null)
throw new NullPointerException(); int c = ctl.get();
// corePoolSize=0,所以不会走这个分支
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 把任务放进队列。
// newCachedThreadPool使用的队列是SynchronousQueue,当没有线程因take阻塞时,offer返回false。
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
//如果工作线程数为0,创建工作线程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 如果入队失败,则创建工作线程
else if (!addWorker(command, false))
reject(command);
}

cachedThreadPool 的一个特点是:工作线程执行完任务后,继续从工作队列获取任务(poll),等待60秒,超时则返回 null。task为 null时,工作线程就退出了 while 循环,也就是说这个线程要死了。

while (task != null || (task = getTask()) != null) {...}

3. newScheduledThreadPool

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//对应ThreadPoolExecutor的设置
this.corePoolSize = corePoolSize;
this.maximumPoolSize = Integer.MAX_VALUE;
this.workQueue = new DelayedWorkQueue();
this.keepAliveTime = TimeUnit.NANOSECONDS.toNanos(0);
this.threadFactory = Executors.defaultThreadFactory();
this.handler = defaultHandler;

分析定时器延迟队列的 take 方法:DelayedWorkQueue 的底层是堆,访问堆顶的任务,如果任务的时间到了,则返回,否则等待直到时间到来。

// ScheduledThreadPoolExecutor.DelayedWorkQueue
public RunnableScheduledFuture take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
RunnableScheduledFuture first = queue[0];
if (first == null)
available.await();
else {
long delay = first.getDelay(TimeUnit.NANOSECONDS);
if (delay <= 0)
return finishPoll(first);
else if (leader != null)
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
available.awaitNanos(delay);
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
if (leader == null && queue[0] != null)
available.signal();
lock.unlock();
}
}

可以看出,3种线程池的主要区别是使用的队列不同。

4. DefaultThreadFactory

static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix; DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
} public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false); //设置为前台线程
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}

如果 Runnable 任务抛出了异常,线程池的工作线程还在吗?在的,线程会 terminate 掉,然后添加一个新的 Worker

Executors类的newFixedThreadPool, newCachedThreadPool, newScheduledThreadPool的更多相关文章

  1. java.util.concurrent.Executors类的常用方法介绍

    Java 线程池 Executors提供了几种线程池实现? 5个,分别如下 1.newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收 ...

  2. Executors 类是什么?

    Executors 为 Executor,ExecutorService,ScheduledExecutorService, ThreadFactory 和 Callable 类提供了一些工具方法. ...

  3. 【Java/Android性能优化1】Android性能调优

    本文参考:http://www.trinea.cn/android/android-performance-demo/ 本文主要分享自己在appstore项目中的性能调优点,包括同步改异步.缓存.La ...

  4. Android性能调优

    本文主要分享自己在appstore项目中的性能调优点,包括同步改异步.缓存.Layout优化.数据库优化.算法优化.延迟执行等.一.性能瓶颈点整个页面主要由6个Page的ViewPager,每个Pag ...

  5. 【java线程池】

    一.概述 1.线程池的优点 ①降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗: ②提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行: ③方便线程并发数的管控,线 ...

  6. java笔记--问题总结

    1. 垃圾回收算法 标记-清除算法 标记-清除算法是最基本的算法,和他的名字一样,分为两个步骤,一个步骤是标记需要回收的对象.在标记完成后统一回收被标记的对象.这个算法两个问题.一个是效率问题,标记和 ...

  7. Android性能调优实例

    本文主要分享自己在appstore项目中的性能调优点,包括同步改异步.缓存.Layout优化.数据库优化.算法优化.延迟执行等. 目前性能优化专题已完成以下部分: 性能优化总纲——性能问题及性能调优方 ...

  8. JUC——检视阅读

    JUC--检视阅读 参考资料 JUC知识图参考 JUC框架学习顺序参考 J.U.C学习总结参考,简洁直观 易百并发编程,实践操作1,不推荐阅读,不及格 JUC文章,带例子讲解,可以学习2 Doug L ...

  9. 面试【JAVA基础】多线程

    本次整理的内容如下: 1.进程与线程的区别 进程是一个可执行的程序,是系统资源分配的基本单位:线程是进程内相对独立的可执行单元,是操作系统进行任务调度的基本单位. 2.进程间的通信方式 2.1.操作系 ...

随机推荐

  1. P4336 [SHOI2016]黑暗前的幻想乡

    P4336 [SHOI2016]黑暗前的幻想乡 矩阵树定理(高斯消元+乘法逆元)+容斥 ans=总方案数 -(公司1未参加方案数 ∪ 公司2未参加方案数 ∪ 公司3未参加方案数 ∪ ...... ∪ ...

  2. P3901 数列找不同

    P3901 数列找不同 题目描述 现有数列 \(A_1,A_2,\cdots,A_N\) ,Q 个询问 \((L_i,R_i)\) , \(A_{Li} ,A_{Li+1},\cdots,A_{Ri} ...

  3. HBase底层存储原理——我靠,和cassandra本质上没有区别啊!都是kv 列存储,只是一个是p2p另一个是集中式而已!

    理解HBase(一个开源的Google的BigTable实际应用)最大的困难是HBase的数据结构概念究竟是什么?首先HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库.另一个不 ...

  4. Facebook广告API系列 1

    Facebook广告API系列 1 前言 最近遇到大坑了,居然要去对接facebook的广告API,之前以为是跟鹅厂一样的API体系,看了半天Facebook的文档,冷汗直冒.... 这得一点一点的讲 ...

  5. UVa 11300 分金币

    https://vjudge.net/problem/UVA-11300 题意: 圆桌上有n个人,每个人都有一定的初始金币,每个人可以给他旁边的人一些金币,最终使每个人的金币数相等.计算最少需要转手的 ...

  6. go 内建变量类型

    bool,string (u)int,(u)int8,(u)int16,(u)int32,(u)int64,uintptr(指针) byte,rune(字符) float32,float64,comp ...

  7. python input选择

    例1 import sys #声明字符串数组并初始化 newspaper=['1.北京晚报','2.作家文摘','3.参考消息', \ '4.证券报','5.不需要'] #字符串数组的输出 ): pr ...

  8. SQLServer中round函数

    ---SQL四舍五入问题1: SELECT CAST('123.456' as decimal) ---123 将会得到 123(小数点后面的将会被省略掉). ---如果希望得到小数点后面的两位.则需 ...

  9. Spring 注解 @Resource和@Autowired

    @Resource和@Autowired两者都是做bean的注入使用. 其实@Resource并不是Spring的注解,他的包是javax.annotation.Resource 需要导入.但是Spr ...

  10. Win7下怎么设置让远程桌面连接记住密码下次登录不需再输入

    远程桌面连接功能想必大家都不会陌生吧,特别是使用VPS服务器的用户们经常会用到,为了服务器的安全每次都会把密码设置的很复制,但是这样也有一个麻烦,就是每次要桌面远程连接的时候都要输入这么复杂的密码,很 ...