1.newFixedThreadPool,该线程池使用的是一个无界队列,即会往队列中不断增加任务,如果新增任务的速度大于处理任务的速度,那么有可能会造成内存耗尽.
//创建方式
ExecutorService executorFixed = Executors.newFixedThreadPool(5);
//查看源码
从源码得知,该线程池用的LinkedBlockingQueue阻塞队列,该阻塞队列如果没有设置数量,默认为Integer.MAX_VALUE 核心线程数和最大线程数是一样的.
2.newSingleThreadExecutor,从名字可以得知该线程池为单线程线程池.
//创建方式
ExecutorService executorSingle = Executors.newSingleThreadExecutor();
查看源码:
从源码得知,发现核心线程数和最大线程数都为1.
代码示例是否是单线程执行:
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + System.currentTimeMillis());
} catch (Exception e) {
}
}
};
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(runnable, ("Thread-" + i));
executorSingle.execute(thread);
}
测试结果:
3.newCachedThreadPool,这个线程池使用的是SynchronousQueue同步队列,即队列中不存储任务,一旦有新的任务,会不断创建线程去执行任务. 当线程池中没有线程时,该线程池会自动关闭.
//创建方式
ExecutorService executorCache = Executors.newCachedThreadPool();
查看源码:
发现核心线程数为0,最大线程数为Integer.MAX_VALUE,使用的是SynchronousQueue队列.
代码示例该线程池会自动关闭:
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + System.currentTimeMillis());
} catch (Exception e) {
}
}
};
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(runnable, ("Thread-" + i));
executorCache.execute(thread);
}
测试结果:
在等待60秒之后,该线程池会自动关闭,由此得知如果核心线程数设置为0,当线程活跃时间到后,线程池会自动关闭.
4.自定义线程池.即线程池中的所有参数都自己设置.
// 核心线程数
protected static int CORE_THREAD_POOL = 10;
//最大线程数
private static int MAX_THREAD_POOL = 20;
//线程存活时间
private static long live = 10;
//存放任务的阻塞队列
private static ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10);
//任务已满,并且线程数已经为最大线程数,此时还有新增任务,会执行对应的策略,该策略为抛出异常
private static ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();
/**
* 自定义线程,参数全部是自己设置的.
*/
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(CORE_THREAD_POOL, MAX_THREAD_POOL, live,
TimeUnit.SECONDS, queue, abortPolicy);
测试拒绝策略报异常:
将核心线程设置为1,最大线程设置为2,阻塞队列容量设置为1
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
};
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(runnable, ("Thread-" + i));
poolExecutor.execute(thread);
}
结果:
拒绝策略的方式有好几种,详细可自己去了解.
5.线程池是如何调度的?
1.当调用线程池执行任务时,会创建线程,当创建的线程大于核心线程数时.会将任务存放到阻塞队列中.线程执行完当前任务后,会继续从阻塞队列中获取任务执行.
2. 如果阻塞队列的容量满了,线程池会重新创建线程去执行队列里的任务.线程池创建的最大线程数不超过定义的最大线程数.
3. 如果阻塞队列的容量满了,并且线程池池中的线程等于最大线程数,这时还有新增任务,这个时候线程池会调用定义的拒绝策略.