线程池的参数和线程池的工作原理及其使用Executors框架创建四种线程池作为面试的高频题,现整理如下:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线程池的参数和线程池的工作原理及其使用Executors框架创建四种线程池
*
* corePoolSize:线程池保留的最小线程数。如果线程池中的线程少于此数目,则执行execut()时创建。
* maximumPoolSize:线程池中允许拥有的最大线程数。
* keepAliveTime、unit:当线程闲置时,保持线程存活的时间。默认情况下,只有当线程池中的线程数大于corePoolSize,才起作用
* threadFactory:线程工厂类
* workQueue:工作队列,存放提交的等待任务,其中有队列大小的限制。
* ArrayBlockingQueue:一个有数组结构组成的有界阻塞队列
* LinkedBlockingQueue:一个由链表组成的有界阻塞队列,而在未指明容量时,容量默认为Integer.MAX_VALUE.
* linkedBlockingDeque:使用双向队列实现的双端阻塞队列,双端意味着可以像普通队列一样先进先出,也可以像栈一样后进先出
* PriorityBlockingQueue:一个支持有线及排序的无界阻塞队列,对元素没有要求,可以实现compareable接口,也可以提供Comparator来对
* 队列中的元素进行比较,跟时间没有任何关系,紧急按照优先级去任务。
* DelayQueue:同PriorityBlockingQueue,也是二叉树实现的优先级阻塞队列。要求元素实现delayed接口,通过执行延时队列提出任务,没有
* 到时间任务取不出来
* SynchronousQueue:一个不存储元素的阻塞队列,消费者线程调用take()方法的时候就会发生阻塞,只到有一个生产者线程生产了一个元素
* 消费者线程就可以拿到这个元素并返回;生产者线程调用put()方法的时候也会被阻塞,直到有一个消费者线程消费了这个元素,生产者才会返回。
*
* 线程池的工作原理:
* 1、如果当前运行的线程数少于corePoolSize(核心线程数),则创建新线程来执行任务
* 2、如果运行的线程等于或者多于corepoolsize,则将任务加入BlockingQueue
* 3、如果无法将任务加入Blockingqueue(队列已满),则在非corePool中创建新的线程来处理任务。
* 4、如果创建新此案城将是当前运行的线程超出了maximumPoolSize,任务将被拒绝,并执行任务饱和策略。
*
*
* 使用Executors框架创建四种线程池
* 1、newCachedTheadPool:创建一个可缓存线程池,如果线程池长度超过处理需求,可以灵活回收空闲线程,若无可回收,则新建线程。
* 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
* 2、newFixedThreadPool:创建一个定长线程池,可以控制线程的最大并发数,超出的此案城会在队列中等待。定长线程池的大小最好根据系统
* 资源进行设置
* 3、newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
* 4、newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。
*
*/
public class TestThreadPoolExecutor {
//创建一个可重用固定个数的线程池
private static ThreadPoolExecutor fixedThreadPool =new ThreadPoolExecutor(1,2,0L, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(1));
public static void main(String[] args) {
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try{
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
});
printCount();
System.out.println("加入第一个任务,线程池刚刚初始化,没有任何可以执行的任务的核心线程,创建一个核心线程来执行任务");
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
});
printCount();
System.out.println("加入第二个任务,没有可以执行任务的核心线程,且任务数大于corepoolsize,新加入的任务放在阻塞队列中");
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
});
printCount();
System.out.println("加入第三个任务,此时阻塞队列已经满了,新建非核心线程执行新加入任务");
try {
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
printCount();
System.out.println("第一个任务执行完毕,核心线程空闲,阻塞队列的任务被取出来,使用核心线程来执行");
try {
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
printCount();
System.out.println("第二个任务执行完毕,核心线程空闲,非核心线程在执行第三个任务");
try {
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
printCount();
System.out.println("第三个任务执行完毕,非核心线程被销毁,核心线程保留");
}
private static void printCount(){
System.out.println("=============");
System.out.println("当前活跃线程数"+fixedThreadPool.getActiveCount());
System.out.println("当前核心线程数"+fixedThreadPool.getCorePoolSize());
System.out.println("阻塞队里中的任务数"+fixedThreadPool.getQueue().size());
}
}