简单理解,线程池实际上就是一个线程可以复用的队列。
执行方法核心源码分析:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();//获取当前线程数
if (workerCountOf(c) < corePoolSize) {//当工作线程小于核心线程数时
if (addWorker(command, true))//添加工作线程
return;//如果添加成功直接返回
c = ctl.get();//获取添加后的线程数
}
//如果当前工作线程数大于核心线程数,则将任务添加到队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果放入workQueue任务失败,则创建线程任务,如果创建线程任务失败,就会调用reject
else if (!addWorker(command, false))
reject(command);
}
创建一个单线程的线程池,只会有一个线程来执行任务,保证所有任务按照指定顺序执行
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
创建拥有固定线程数的线程池,控制线程最大并发,超出的线程会在队列中等待。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
创建一个可缓存线程池,每个线程创建之后都有一定的存活期,如果在存活期间没有需要处理的线程则进行回收,若无可回收,则新建线程。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
创建一个固定线程数的线程池,支持定时及周期性任务执行。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ThreadPoolExecutor(int corePoolSize,//指定了线程池中的线程数量
int maximumPoolSize,//指定线程池中最大线程数
long keepAliveTime,//当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间,即多次时间内会被销毁
TimeUnit unit,//keepAliveTime 的单位
BlockingQueue 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;
}
答:线程的创建和销毁的花销都是比较大的,这些时间有可能比业务处理时间更长。线程池的复用将创建和销毁的步骤省去了。
答:1.效率高(省去了创建销毁的过程);2.方便管理。
答:
阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列。