我们使用线程时,需要new一个,用完了又要销毁,这样频繁的创建销毁也很耗资源,所以就提供了线程池。线程池中有一个线程队列,里面保存着所有等待状态的线程。
基本使用:
和线程池使用Executors来创建
先创建一个线程类:
public class PoolDemo extends Thread {
@Override
public void run() {
System.out.println(this.getName() +"正在运行");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试类:
public class Test {
public static void main(String[] args) {
PoolDemo[] demos = new PoolDemo[100];
for (int i = 0; i < 100; i++) {
demos[i]=new PoolDemo();
demos[i].setName(""+i);
}
ExecutorService pool = Executors.newFixedThreadPool(5);
for (int i = 0; i < 100; i++) {
pool.submit(demos[i]);
}
pool.shutdown();
}
}
运行如下:
可以发现是五个线程五个线程进行运行的。
这是因为线程池的值是5,只能同时管理五个线程
执行流程
当我们使用submit()方法时,会将线程放入线程池队列,然后进入线程执行,如果当前执行的线程已经达到了设置的最大值(这里是5),那么就会进入线程池的队列等待,当线程池有空的时候,进入执行
线程池状态:
- 线程池在构造前(new操作)是初始状态,一旦构造完成线程池就进入了执行状态RUNNING。线程池处于运行状态,随时准备接受任务来执行。
- 线程池运行中可以通过shutdown()和shutdownNow()来改变运行状态。shutdown()是一个平缓的关闭过程,也就是
优雅关闭
,线程池停止接受新的任务,同时等待已经提交的任务执行完毕,包括那些进入队列还没有开始的任务,这时候线程池处于SHUTDOWN状态;shutdownNow()是一个立即关闭
过程,线程池停止接受新的任务,同时线程池取消所有执行的任务和已经进入队列但是还没有执行的任务,这时候线程池处于STOP状态。 - 一旦shutdown()或者shutdownNow()执行完毕,线程池就进入TERMINATED状态,此时线程池就结束了。
- isTerminating()描述的是SHUTDOWN和STOP两种状态。
isShutdown()描述的是非RUNNING状态,也就是SHUTDOWN/STOP/TERMINATED三种状态。
总结:
- 线程池有运行、关闭、停止、结束四种状态,结束后就会释放所有资源 优雅关闭线程池使用shutdown()
- 立即关闭线程池使用shutdownNow(),同时得到未执行的任务列表
- 定时或者永久等待线程池关闭结束使用awaitTermination()操作
线程池任务拒绝策略(线程池队列已满的情况)
线程池有一个任务队列,用于缓存所有待处理的任务,即将处理的任务将从任务队列中移除。因此在任务队列长度有限的情况下就会出现新任务的拒绝处理问题,需要有一种策略来处理应该加入任务队列却因为队列已满无法加入的情况。另外在线程池关闭的时候也需要对任务加入队列操作进行额外的协调处理。
我们使用 RejectedExecutionHandler 类提供任务拒绝策略:
- 直接丢弃任务(
DiscardPolicy
) - 丢弃队列中的最旧任务(
DiscardOldestPolicy
) - 抛出异常RejectedExecutionException (
AbortPolicy
) - 不用线程池执行(
CallerRunsPolicy
),将被调用者线程进行执行
测试:
public class PoolDemo extends Thread {
@Override
public void run() {
System.out.println(this.getName() +"正在运行");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
1,1,0, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(2));
//直接丢弃策略
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
//丢弃最近
// pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
//抛出异常
// pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
PoolDemo[] demos = new PoolDemo[100];
for (int i = 0; i < 100; i++) {
demos[i]=new PoolDemo();
demos[i].setName(""+i);
}
for (int i = 0; i < 100; i++) {
pool.submit(demos[i]);
}
}
}
运行如下:
可以发现后面的任务都被抛弃。
当使用抛弃最旧时,运行如下:
最旧的都被抛弃,留下了98和99