目录
1.线程池概
2 为什么要使用线程池
1创建线程问题
2解决上面两个问题思路:
3线程池的好处
4线程池适合应用场景
3 线程池的构造函数参数
1.corePoolSize int 线程池核心线程大小
2.maximumPoolSize int 线程池最大线程数量
3.keepAliveTime long 空闲线程存活时间
4.unit 空闲线程存活时间单位
5.workQueue BlockingQueue 工作队列
①ArrayBlockingQueue
②LinkedBlockingQuene
③SynchronousQuene
④PriorityBlockingQueue
6.threadFactory ThreadFactory 线程工厂
7.handler RejectedExecutionHandler 拒绝策略
①CallerRunsPolicy
8.添加线程例子
例如饭店的桌子的故事:
线程池的而实际例子:
4增减线程的特点
5线程池手动创建还是自动创建
1自动创建好处
2自动创建可能带来哪些问题
1.newFixedThreadPool
2.newSingleThreadExecutor
3.newCachedThreadPool
3正确创建线程池的方法
4线程池里的线程数量设定多少比较适合
6停止线程的正确方法
1.shutdown
2isShutdown
3.isTerminated
4.awaitTermination
5.shutdownNow
7.线程池拒绝策略
1.拒绝时机
2.四种拒绝策略
1.概述
8.钩子方法
1.每个任务执行之前之后暂停恢复模拟日志、统计
9.线程池原理
1.线程池组成部分
2.线程管理器
3.工作线程
4.任务列队
5.任务接口
1.线程池概
软件中的池,就是提前创建好了东西放在池子里,你直接去池子里拿去用就行了,有现成的可用的,节省了你临时创建的时间。
我们的资源是有限的,比如就10个线程,创造一个10个线程的线程池。
线程池中创建的线程,可以重复使用,可以控制资源总量。
如果不使用线程池,每个任务都开一个新线程处理
1.1个线程
2.for循环创建线程
3.当任务量生成1000个时
public class EveryTaskOneThread {
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
Thread thread = new Thread(new Task());
thread.start();
}
}
static class Task implements Runnable{
@Override
public void run() {
System.out.println("执行了任务!");
}
}
}
这样开销太大,我们希望有固定数量的线程,
来执行这1000个线程,
这样就避免了反复创建并销毁线程所带来的开销问题。
2 为什么要使用线程池
1创建线程问题
- 反复创建线程开销大
- 过多的线程会占用大多内存
2解决上面两个问题思路:
- 用少量线程-避免内存占用过多
- 让这部分线程都保持工作,且可以反复执行任务-避免生命周期的损耗
3线程池的好处
- 加快响应速度
- 合理利用CPU和内存
- 统一归管理资源
4线程池适合应用场景
- 服务器接收大量请求时,使用线程池 是非常合适的,他可以大大减少线程池的创建和销毁次数,提高服务器的工作效率
- 实际开发中,如果需要创建5个以上的线程,那么就可以使用线程池来管理
3 线程池的构造函数参数
1.corePoolSize int 线程池核心线程大小
线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。任务提交到线程池后,首先会检查当前线程数是否达到了corePoolSize,如果没有达到的话,则会创建一个新线程来处理这个任务。
是否需要添加线程规则
2.maximumPoolSize int 线程池最大线程数量
当前线程数达到corePoolSize后,如果继续有任务被提交到线程池,会将任务缓存到工作队列(后面会介绍)中。如果队列也已满,则会去创建一个新线程来出来这个处理。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。
3.keepAliveTime long 空闲线程存活时间
一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定
4.unit 空闲线程存活时间单位
keepAliveTime的计量单位
5.workQueue BlockingQueue 工作队列
新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列:
①ArrayBlockingQueue
基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。
②LinkedBlockingQuene
基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而基本不会去创建新线程直到maxPoolSize(很难达到Interger.MAX这个数),因此使用该工作队列时,参数maxPoolSize其实是不起作用的。
③SynchronousQuene
一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。
④PriorityBlockingQueue
具有优先级的无界阻塞队列,优先级通过参数Comparator实现。
6.threadFactory ThreadFactory 线程工厂
创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等
新的线程是由ThreadFactory创建的,默认使用Executors.defaultThreadFactory0,创建出来的线程都在同个线程组,拥有同样的NORM PRIORITY优先级并且都不是守护线程。如果自己指定ThreadFactory,那么就可以改变线程名、线程组、优先级、是否是守护线程等
通常使用默认的即可
7.handler RejectedExecutionHandler 拒绝策略
当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略:
①CallerRunsPolicy
该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。
②AbortPolicy
该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。
③DiscardPolicy
该策略下,直接丢弃任务,什么都不做。
④DiscardOldestPolicy
该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列
8.添加线程例子
例如饭店的桌子的故事:
饭店屋子里面10个桌子,这10个桌子是一直存在的。是corePoolSize。
生意火爆,里面桌子坐满了,需要使用临时桌子,放到饭店门口。是maxPoolSize。在收摊的时候外面的椅子会收回来的。里面的桌子不会处理,一直会等待。
线程池的而实际例子:
线程池:核心池大小5,最大池大小为10,队列为100
线程池中的请求最多创建5个,然后任务被添加到队列中,直到达到100.当队列已满时,将创建最新的线程。maxPoolSize。最多10个线程,如果再来任务,就拒绝。
4增减线程的特点
- 通过设置corePoolSize和maximunPoolSize相同,就可以创建固定大小的线程池
- 线程池希望保持更小的线程数量,并且只有在负载变得很大的时候才去增加他
- 通过设置maximunPoolSize为很高的值,可以允许线程池容纳任意数量的并发任务
- 只有队列满的时才会创建多余corePoolSize的线程,如果使用无界队列(LinkedBlockingQueue),那么线程数就不会超过corePoolSize
5线程池手动创建还是自动创建
1自动创建好处
- 手动创建更好,因为这样可以让我们更加明确线程池创建的规则,避免资源耗尽的风险。
2自动创建可能带来哪些问题
1.newFixedThreadPool
传进去的LinkedBlockingQueue是没有容量限制的,所以当请求数量越来越多。并且无法及时处理完的时候,也就会请求堆积,会很容易造成占用大量内存。可能会导致oom
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(4);
for (int i = 0; i < 100; i++) {
executorService.execute(new Task());
}
}
static class Task implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread());
}
}
}
错误案例
修改idea内存配置 -Xmx1m -Xms1m
没有点击Modify options,然后add即可
应用之后启动下面代码
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 演示newFixedThreadPool出错的情况
*/
public class FixedThreadPoolOOMTest {
private static ExecutorService executorService = Executors.newFixedThreadPool(1);
public static void main(String[] args) {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
executorService.execute(new Task());
}
}
static class Task implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread());
try {
Thread.sleep(500000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
控制台打印如下
2.newSingleThreadExecutor
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExcutor {
public static void main(String[] args) {
// 单独的线程不需要传参数,线程数默认1
/*
* public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
* */
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 100; i++) {
executorService.execute(new Task());
}
}
static class Task implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread());
}
}
}
3.newCachedThreadPool
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadExcutor {
public static void main(String[] args) {
// 无界线程池,具有自动回收对于线程的功能
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(new Task());
}
}
static class Task implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread());
}
}
}
3正确创建线程池的方法
- 根据不同的业务场景,自己设置线程池参数,比如我们的内存有多大,我们想给线程取什么名字等等。
4线程池里的线程数量设定多少比较适合
创建多少线程合适,要看多线程具体的应用场景。我们的程序一般都是 CPU 计算和 I/O 操作交叉执行的,由于 I/O 设备的速度相对于 CPU 来说都很慢,所以大部分情况下,I/O 操作执行的时间相对于 CPU 计算来说都非常长,这种场景我们一般都称为 I/O 密集型计算;和 I/O 密集型计算相对的就是 CPU 密集型计算了,CPU 密集型计算大部分场景下都是纯 CPU 计算。I/O 密集型程序和 CPU 密集型程序,计算最佳线程数的方法是不同的。
下面我们对这两个场景分别说明。
对于 CPU 密集型计算,多线程本质上是提升多核 CPU 的利用率,所以对于一个 4 核的 CPU,每个核一个线程,理论上创建 4 个线程就可以了,再多创建线程也只是增加线程切换的成本。所以,对于 CPU 密集型的计算场景,理论上“线程的数量 =CPU 核数”就是最合适的。不过在工程上,线程的数量一般会设置为“CPU 核数 +1”,这样的话,当线程因为偶尔的内存页失效或其他原因导致阻塞时,这个额外的线程可以顶上,从而保证 CPU 的利用率。
对于 I/O 密集型的计算场景,比如前面我们的例子中,如果 CPU 计算和 I/O 操作的耗时是 1:1,那么 2 个线程是最合适的。如果 CPU 计算和 I/O 操作的耗时是 1:2,那多少个线程合适呢?是 3 个线程,如下图所示:CPU 在 A、B、C 三个线程之间切换,对于线程 A,当 CPU 从 B、C 切换回来时,线程 A 正好执行完 I/O 操作。这样 CPU 和 I/O 设备的利用率都达到了 100%。
CPU密集型(加密、计算hash等): 最佳线程数为CPU核心数的1-2倍左右。
耗时IO型(读写数据库、文件、网络读写等):最佳线程数般会大于cpu核心数很多倍,以JVM线程监控显示繁忙情况头依据,保证线程空闲可以衔接上
参考Brain Goetz推荐最终终计算方法: 线程数=CPU核心数*( 1+平均等待时间/平均工作时间)
6停止线程的正确方法
1.shutdown
对于线程池而言,拒绝后面新的的任务,存量任务执行完会关闭
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 演示关闭线程
*/
public class ShuntDown {
public static void main(String[] args) throws InterruptedException {
// 创建10个固定的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.execute(new ShuntDownTask());
}
Thread.sleep(500);
executorService.shutdown();
// 再提交新的任务,提交不进去
for (int i = 0; i < 1000; i++) {
executorService.execute(new ShuntDownTask());
}
}
static class ShuntDownTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
控制台打印,可以看到后面的任务没有被执行
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task cn.butool.threadpool.ShuntDown$ShuntDownTask@29453f44 rejected from java.util.concurrent.ThreadPoolExecutor@5cad8086[Shutting down, pool size = 10, active threads = 10, queued tasks = 0, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at cn.butool.threadpool.ShuntDown.main(ShuntDown.java:20)
pool-1-thread-9
pool-1-thread-1
pool-1-thread-2
pool-1-thread-5
pool-1-thread-6
pool-1-thread-3
pool-1-thread-4
pool-1-thread-8
pool-1-thread-7
pool-1-thread-10
Process finished with exit code 1
2isShutdown
isShutDown当调用shutdown()方法后返回为true。
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 演示关闭线程
*/
public class ShuntDown {
public static void main(String[] args) throws InterruptedException {
// 创建10个固定的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.execute(new ShuntDownTask());
}
Thread.sleep(500);
System.out.println(executorService.isShutdown());
executorService.shutdown();
System.out.println(executorService.isShutdown());
}
static class ShuntDownTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
pool-1-thread-2
pool-1-thread-5
pool-1-thread-6
pool-1-thread-10
pool-1-thread-9
pool-1-thread-1
pool-1-thread-4
pool-1-thread-7
pool-1-thread-8
false
pool-1-thread-3
true
3.isTerminated
isTerminated当调用shutdown()方法后,并且所有提交的任务完成后返回为true
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 演示关闭线程
*/
public class ShuntDown {
public static void main(String[] args) throws InterruptedException {
// 创建10个固定的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.execute(new ShuntDownTask());
}
Thread.sleep(500);
System.out.println(executorService.isShutdown());
executorService.shutdown();
System.out.println(executorService.isTerminated());
}
static class ShuntDownTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打印
pool-1-thread-10
pool-1-thread-3
pool-1-thread-4
pool-1-thread-7
pool-1-thread-8
false
pool-1-thread-9
pool-1-thread-6
false
pool-1-thread-5
pool-1-thread-2
pool-1-thread-1
缩小任务查看
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 演示关闭线程
*/
public class ShuntDown {
public static void main(String[] args) throws InterruptedException {
// 创建10个固定的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 1; i++) {
executorService.execute(new ShuntDownTask());
}
Thread.sleep(500);
System.out.println(executorService.isShutdown());
executorService.shutdown();
System.out.println(executorService.isTerminated());
}
static class ShuntDownTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打印
false
pool-1-thread-1
true
4.awaitTermination
有时场景需要主线程等各子线程都运行完毕后再执行。这时候就需要用到ExecutorService接口中的awaitTermination方法
package cn.butool.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 演示关闭线程
*/
public class ShuntDown {
public static void main(String[] args) throws InterruptedException {
// 创建10个固定的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.execute(new ShuntDownTask());
}
Thread.sleep(500);
executorService.shutdown();
//该方法调用会被阻塞,并且在以下几种情况任意一种发生时都会导致该方法的执行:
// 即shutdown方法被调用之后,或者参数中定义的timeout时间到达或者当前线程被打断,
// 这几种情况任意一个发生了都会导致该方法在所有任务完成之后才执行。
// 第一个参数是long类型的超时时间,第二个参数可以为该时间指定单位。
System.out.println(executorService.awaitTermination(3, TimeUnit.SECONDS));
}
static class ShuntDownTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
控制台打印
pool-1-thread-2
pool-1-thread-3
pool-1-thread-7
pool-1-thread-6
pool-1-thread-4
pool-1-thread-8
pool-1-thread-5
pool-1-thread-1
pool-1-thread-9
pool-1-thread-10
true
Process finished with exit code 0
5.shutdownNow
shutdownNow调用的是中断所有的Workers,shutdownNow会把所有任务队列中的任务取出来,返回一个任务列表。
package cn.butool.threadpool;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 演示关闭线程
*/
public class ShuntDown {
public static void main(String[] args) throws InterruptedException {
// 创建10个固定的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.execute(new ShuntDownTask());
}
Thread.sleep(1500);
// 立刻关闭掉线程池,返会没有执行的任务列表
List<Runnable> runnables = executorService.shutdownNow();
System.out.println("被中断数量"+runnables.size());
}
static class ShuntDownTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
System.out.println("被中断了"+Thread.currentThread().getName());
}
}
}
}
控制台打印
pool-1-thread-3
pool-1-thread-9
pool-1-thread-10
pool-1-thread-6
pool-1-thread-5
pool-1-thread-2
pool-1-thread-1
pool-1-thread-8
pool-1-thread-7
pool-1-thread-4
pool-1-thread-3
pool-1-thread-1
pool-1-thread-4
pool-1-thread-9
pool-1-thread-10
pool-1-thread-6
pool-1-thread-5
pool-1-thread-2
pool-1-thread-8
pool-1-thread-7
被中断了pool-1-thread-7
被中断了pool-1-thread-5
被中断了pool-1-thread-6
被中断了pool-1-thread-9
被中断了pool-1-thread-3
被中断了pool-1-thread-1
被中断了pool-1-thread-2
被中断了pool-1-thread-10
被中断了pool-1-thread-4
被中断了pool-1-thread-8
被中断数量70
Process finished with exit code 0
7.线程池拒绝策略
1.拒绝时机
- Executors关闭时提交新任务会拒绝
- Executors最大线程和工作队列容量使用优先边界并且已经饱和
2.四种拒绝策略
1.概述
拒绝策略提供顶级接口 RejectedExecutionHandler ,其中方法 rejectedExecution 即定制具体的拒绝策略的执行逻辑。
jdk默认提供了四种拒绝策略
2.AbortPolicy - 抛出异常,中止任务。抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行
3.CallerRunsPolicy - 使用调用线程执行任务。当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大
4.DiscardPolicy - 直接丢弃,其他啥都没有
5.DiscardOldestPolicy - 丢弃队列最老任务,添加新任务。当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
8.钩子方法
1.每个任务执行之前之后暂停恢复模拟日志、统计
package cn.butool.threadpool;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 每个任务执行的前后放钩子函数
*/
public class SuspendThreadPoolTest extends ThreadPoolExecutor {
public SuspendThreadPoolTest(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public SuspendThreadPoolTest(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public SuspendThreadPoolTest(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public SuspendThreadPoolTest(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
/**
* 重写方法
* @param t
* @param r
*/
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
lock.lock();
try {
while (isPaused){
unPaused.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
private boolean isPaused;
private final ReentrantLock lock= new ReentrantLock();
private Condition unPaused=lock.newCondition();
private void usePaused(){
// 枷锁
lock.lock();
try {
isPaused=true;
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放锁
lock.unlock();
}
}
/**
* 恢复函数
*/
private void resume(){
// 枷锁
lock.lock();
try {
isPaused=false;
unPaused.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放锁
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
SuspendThreadPoolTest suspendThreadPoolTest = new SuspendThreadPoolTest(5,
10,
20,TimeUnit.SECONDS,
new LinkedBlockingDeque<>());
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("我被执行"+Thread.currentThread().getName());
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
};
for (int i = 0; i < 10000; i++) {
suspendThreadPoolTest.execute(runnable);
}
Thread.sleep(1500);
//线程池暂停
suspendThreadPoolTest.usePaused();
System.out.println("线程池被暂停了");
Thread.sleep(1500);
suspendThreadPoolTest.resume();
System.out.println("线程池被恢复了");
}
}
9.线程池原理
1.线程池组成部分
1.线程管理器
2.工作线程
3.任务列队
4.任务接口