ThreadPoolExecutor:之前创建的各种线程池,实际都是通过调用该类的构造方法创建的。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
各参数的意义:
- corePoolSize:线程池的核心线程数,当核心线程数被创健后,即使没有任务执行了,默认也会存活。当allowCoreThreadTimeOut为true,核心线程也会被回收。
- maximumPoolSize:线程池允许的最大线程数。除去核心线程,其他的就是非核心线程,他们会在需要时创建,空闲时间超过keepAliveTime后会被回收。
- keepAliveTime: 指的是空闲线程结束的超时时间;
- unit :是一个枚举,表示 keepAliveTime 的单位;
- workQueue:表示存放任务的BlockingQueue<Runnable队列。
- BlockingQueue:阻塞队列(BlockingQueue)是java.util.concurrent下的主要用来控制线程同步的工具。如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒。同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作。
- threadFactory:线程工厂类,当不指定时,会使用默认工厂类。可以自定义一个线程工厂类,在newThread方法中对线程的一些属性进行自定义设置。
public interface ThreadFactory {
Thread newThread(Runnable r);
}
- handler 拒绝策略,当线程数已最大,队列也满了的时候,用来处理新的任务。可自定义。
public interface RejectedExecutionHandler { void rejectedExecution(Runnable r, ThreadPoolExecutor executor); }
ThreadPoolExecutor已实现了四种拒绝策略:
-
AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满。默认拒绝策略
public static class AbortPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
- DisCardPolicy:不执行新任务,也不抛出异常
public static class DiscardPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
- DisCardOldSetPolicy:将消息队列中的第一个任务删除,然后重新提交当前任务。
public static class DiscardOldestPolicy implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }
- CallerRunsPolicy:直接调用execute来执行当前任务。这个策略不想放弃任务,直接该execute的线程本身来执行。
线程池的执行过程:public static class CallerRunsPolicy implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
- 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
- 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
- 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
- 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么执行拒绝策略。
所以我们也可以根据需要自定义线程池。
public class MyPool {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(2,4,1000,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue(3),
new MyThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
ArrayList<MyRun> myRuns = new ArrayList<>();
//任务10大于4+3=7
for (int i = 0; i < 10; i++) {
MyRun run = new MyRun();
myRuns.add(run);
}
for (MyRun myRun : myRuns) {
executor.execute(myRun);
}
}
}
class MyThreadFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
return t;
}
}
class MyRun implements Runnable{
private static int num = 0;
//保证创建的每个MyRun都有不同的id
private final int id =num++;
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" "+id);
}
}
输出结果:
这里使用的是第四种拒绝策略,为了不放弃任务,调用了主线程执行任务。也可以设置其他策略查看效果。