看一下线程池的核心类ThreadPoolExecutor中的构造器
它有七个参数
int corePoolSize:
这个参数是线程池核心工作线程,就像去银行一样,他所有的窗口不一定都开。假设银行总共有6个窗口,开了三个,这3个就是我们的核心线程数即corePoolSize。
int maximumPoolSize:
这个参数是最大线程数的意思。就像上面的例子说的银行总共开了6个窗口,这6个窗口就是线程池最大承担同时工作的线程的个数。
就是最多可以同时有多少个窗口同时工作。
BlockingQueue<Runnable> workQueue:
这个参数是阻塞队列,当我们在银行班业务时,往往不是所有的窗口都是开的,一般只会开一部分,人多了的话就会进入银行的等待区,线程池也是这么设计,这个阻塞队列就是用来存储因为线程工作空间被占用,而只能等待在等候区的线程。但是当我们的等候区的线程也满了的时候,有工作任务再次被丢进来了,线程池会再次申请开新的线程,就像银行候客区满的时候,银行为了提高工作效率,会增加窗口,这时候打开所有的窗口,及线程池工作线程达到极限,后面的线程会进入阻塞队列。 RejectedExecutionHandler handler:
这个是线程池的拒绝策略,当线程池已经达到最大极限,并且队列里面也已经满了,就像银行一样,所有窗口都开了,整个银行里面都是人,为了维护银行的安全,当然需要制定一定的策略处理这种线程非常多的情况,对于拒绝策略,这里暂时不做介绍。
long keepAliveTime, 多余的空闲线程的存活时间。就像我们的银行一样,由于人非常多我们把剩下的所有窗口都开了,那么如果我们业务已经处理完了,在非核心线程和队列里面的任务都已经处理完了,那么这个时候这个参数就会有作用了,设置一段时间,如果做完了队列和非核心线程的任务,在这个时间段内没有任务,那么后来新加的窗口,鸡我们的非核心线程数机会慢慢的关闭,直到只剩核心线程数。
当
TimeUnit unit:
这个参数代表这上面非空闲线程存活时间的单位。
ThreadFactory threadFactory:
表示生成线程池中工作线程的工厂,用于创建线程,一般用默认的即可。
下面有一段测试的代码
package juc.threadpool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Description
* @Author DJZ-WWS
* @Date 2019/2/26 16:39
*/
public class ThreadPoolTest {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 3000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.DiscardOldestPolicy());
Runnable myRunnable = () -> {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "run");
} catch (InterruptedException e) {
e.printStackTrace();
}
};
executor.execute(myRunnable);
executor.execute(myRunnable);
executor.execute(myRunnable);
System.out.println("---先开启三个线程---");
System.out.println("核心线程数" + executor.getCorePoolSize());
System.out.println("线程池线程数" + executor.getPoolSize());
System.out.println("队列任务数" + executor.getQueue().size());
executor.execute(myRunnable);
executor.execute(myRunnable);
executor.execute(myRunnable);
System.out.println("---再开启三个线程---");
System.out.println("核心线程数" + executor.getCorePoolSize());
System.out.println("线程池线程程数" + executor.getPoolSize());
System.out.println("队列任务数" + executor.getQueue().size());
Thread.sleep(8000);
System.out.println("----8秒之后----");
System.out.println("核心线程数" + executor.getCorePoolSize());
System.out.println("线程池线程线程池数" + executor.getPoolSize());
System.out.println("队列任务数" + executor.getQueue().size());
executor.shutdown();
}
}
结果如下:
简单的说明:
设置线程核心设置是3个,最大线程数6个
当我们一开我们往线程池里丢了三个任务,每个线程会工作2秒,再线程还没有工作完的时候我们又丢进3个线程这个时候线程会进入阻塞队列,因为队列是空的,所以不会创建新的线程,这时候线程池里面的线程情况是核心线程数3个队列任务个数3个线程池里的线程总数是3个。当过了一段时间之后,所有任务都完成了线程池里面只剩核心线程再工作,所以队列任务数0,核心线程数3个。
这就是线程池的整体工作过程。
下图是线程池的工作原理图
ThreadPoolExecutor中线程执行任务的示意图如下图所示
1.在execute()方法中创建一个线程,让这个线程执行任务
2.这个线程执行完上图中的任务后,会反复从BlockQueue获取任务来执行。
线程池execute方法源码实现如下:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
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);
}
//如果县城内池不处于运行或者任务无法放入队列,并且当前线程数小于最大允许的线程数量,
//则创建一个线程执行任务
else if (!addWorker(command, false))
//抛出RejectedExecutionException
reject(command);
}