线程池的创建可以通过创建ThreadPoolExecutor对象或者调用Executors的工厂方法来创建线程池。但是在阿里巴巴的java开发手册中提到:
ThreadPoolExecutor[强制]线程池不允许使用Executors去创建,而是通过ThreadPoolExecutors的方式, 这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明: Executors 返回的线程池对象的弊端如下:
1.FixedThreadPool 和SingleThreadPool:
允许的请求队列长度为Integer.MAX _VALUE,可能会堆积大量的请求,从而导致OOM。
2. CachedThreadPool 和ScheduledThreadPool:
允许的创建线程数量为Integer.MAX_VALUE, 可能会创建大量的线程, 从而导致OOM.
因此先看一下怎幺通过创建ThreadPoolExecutor对象来创建一个线程池.
public ThreadPoolExecutorfint corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
重要参数的说明:这是ThreadPoolExecutor的构造方法,其中的参数含义如下
corePoolSize:核心浅程池大小,新的任各到线程池后,线程池会创建新的线程(即使有空困线程) , 直到核心线程池已满。2 maximumPoolSize:最大线程池大小,顾名思义,线程池能创建的线程的最大数目keepAliveTime:线程池的工作线程空闲后,保持存活的吋间TimeUnit:吋间単位BlockingQueue Runnables:用来偖存等待抗行任务的队列threadFactory:线程工厂RejrctedExecutionHandler:当队列和线程池都满了时拒绝任务的策略
corePoolSize和maximumPoolSize
默认情况下线程池中的线程初始时为0,当有新的任务到来时才会创建新线程,当线程数目到达corePoolSize的数量时,新的任务会被缓存到workQueue队列中。如果不断有新的任务到来,队列也满了的话,线程池会再新建线程直到总的线程数目达到maximumPoolSize.如果还有新的任务到来,则要根据RejectedExecutionHandler对新的任务进行相应拒绝处理。
BlockingQueue
一个阻塞队列,用来存储等待执行的任务,常用的有如下几种:
- ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO (先进先出)原则对元素进行排序。
2 linkedBlockingQueue: 一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue.静态工厂方法Executors.newFixedThreadPool()使用了这个队列。SynchronousQueue: 一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作, 否则插入操作一直处于阻塞状态,吞吐量通常要高于linkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。PriorityBlockingQueue:一个具有优先级的无限阻塞队列
RejectedExecutionHandler
当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。有下面四种JDK提供的策略:
- AbortPolicy,表示无法处理新任务时抛出异常,默认策略CallerRunsPolicy:用调用者所在线程来运行任务。DiscardOldestPolicy:该策略将丢弃最老的一个请求,也就是丢弃即将被执行的任务,并尝试再次提交当前任务。DiscardPolicy: 不处理,丢弃掉
除了这些JDK提供的策略外,
还可以自己实现RejectedExecutionHandler接口定义策略。
代码示例
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadTest {
public static void main(String[] args) {
//设置核心池大小
int corePoolSize=5;
//设置线程池最大能接受多少线程
int maximumPoolSize=10;
//设置当前线程数大于corePoolSize,小于maximumPoolSize,超出corePoolSize的线程的线程数的生命周期
long keepActiveTime=200;
//设置时间单位
TimeUnit timeUnit = TimeUnit.SECONDS;
//设置线程池缓存队列的排队策略为FIFO,并且指定缓存队列大小为5
BlockingQueueworkQueue=new ArrayBlockingQueue(5);
//根据前面我们的设置参数,来创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepActiveTime,timeUnit,workQueue);
for (int i = 1; i <16 ; i++) {
PoolThread pt = new PoolThread(i);
executor.execute(pt);
System.out.println("线程池中的线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+executor.getQueue().size()+",已执行完的任务数目:"+executor.getCompletedTaskCount());
}
//使用线程池,一定注意,用完后,要自己关掉线程池
executor.shutdown();
}
}
class PoolThread implements Runnable{
//传入一个任务编号
private int num;
public PoolThread(int num) {
this.num=num;
}
@Override
public void run() {
System.out.println("任务"+num+"开始执行");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务"+num+"执行完毕");
}
}
注:个人学习总结



