由于频繁的创建和销毁线程需要消耗时间,所以我们使用线程池来使线程能够复用,
线程池在
public class ThreadPoolExecutor extends AbstractExecutorService
ThreadPoolExecutor是java中线程池的核心类
构造方法:
corePoolSize:核心池的大小
maximumPoolSize:线程池最大线程数
keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。
unit:参数keepAliveTime的时间单位
workQueue:一个阻塞队列,用来存储等待执行的任务
threadFactory:线程工厂,主要用来创建线程;
handler:表示当拒绝处理任务时的策略
线程池的状态:
当创建线程池后,初始时,线程池处于RUNNING状态;
如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;
如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;
当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。
运行原理
默认情况下,创建线程池的时候,线程池中是没有线程的,提交任务之后才会创建线程,[当然也可以用下面两个方法创建创建线程池时创建线程
prestartCoreThread():初始化一个核心线程;
prestartAllCoreThreads():初始化所有核心线程]
类里面最核心的方法是execute()方法,submit()的底层也是调用execute()方法,
如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务;
如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(一般来说是任务缓存队列已满),则会尝试创建新的线程去执行这个任务;
如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略进行处理;
如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。
public class Mytask implements Runnable {
private int taskNum;
public Mytask(int taskNum){
this.taskNum = taskNum;
}
@Override
public void run() {
System.out.println("正在执行task "+taskNum);
try{
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task "+taskNum+"执行完毕");
}
}
public class ThreadPoolDemo {
public static void main(String[] args) {
ThreadPoolExecutor tpe = new ThreadPoolExecutor(5,10,1000, TimeUnit.MICROSECONDS,
new LinkedBlockingDeque<>(5));
for (int i = 0; i < 15; i++) {
Mytask mt = new Mytask(i);
tpe.execute(mt);
System.out.println("线程池中线程的数量"+tpe.getPoolSize()+",队列中等待执行的任务数目:"+
tpe.getQueue().size()+",已执行玩别的任务数目:"+tpe.getCompletedTaskCount());
}
tpe.shutdown();
}
}
结果如下
四种线程池的创建:
①newCachedThreadPool
创建一个线程池,如果线程池中的线程数量过大,它可以有效的回收多余的线程,如果线程数不足,那么它可以创建新的线程。
优点:如果当第二个任务开始,第一个任务已经执行结束,那么第二个任务会复用第一个任务创建的线程,并不会重新创建新的线程,提高了线程的复用率
不足:这种方式虽然可以根据业务场景自动的扩展线程数来处理我们的业务,但是最多需要多少个线程同时处理缺是我们无法控制的;
②newFixedThreadPool
这种方式可以指定线程池中的线程数。举个栗子,如果一间澡堂子最大只能容纳20个人同时洗澡,那么后面来的人只能在外面排队等待。
优点:newFixedThreadPool的线程数是可以进行控制的,因此我们可以通过控制最大线程来使我们的服务器打到最大的使用率,同事又可以保证及时流量突然增大也不会占用服务器过多的资源
③newScheduledThreadPool
该线程池支持定时,以及周期性的任务执行,我们可以延迟任务的执行时间,也可以设置一个周期性的时间让任务重复执行。
④newSingleThreadExecutor
这是一个单线程池,至始至终都由一个线程来执行。