线程池使用FutureTask的时候如果拒绝策略设置为了DiscardPolicy和DiscardOldestPolicy
并且在被拒绝的任务的Future对象上调用无参get方法那么调用线程会一直被阻塞。
阿里巴巴手册
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险
因为:
该任务队列是LinkedBlockingQueue,是无界队列,如果任务数量特别多,可能会导致内存不足
是无界队列
线程池的四种池
1、FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2、CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM
自定义线程池的重要参数含义
1.corePoolSize 指定了线程池里的线程数量
2.maximumPoolSize 指定了线程池里的最大线程数量
3.keepAliveTime 当线程池线程数量大于corePoolSize时候,多出来的空闲线程,多长时间会被销毁。
4.unit 时间单位
5.workQueue 任务队列,用于存放提交但是尚未被执行的任务。
6.threadFactory 线程工厂,用于创建线程,一般可以用默认的
7.handler 拒绝策略,当任务过多时候,如何拒绝任务。
corePoolSize and maximumPoolSize 解释意义流程图
corePoolSize:核心线程数;maximunPoolSize:最大线程数
每当有新的任务到线程池时,
第一步: 先判断线程池中当前线程数量是否达到了corePoolSize,若未达到,则新建线程运行此任务,且任务结束后将该线程保留在线程池中,不做销毁处理,若当前线程数量已达到corePoolSize,则进入下一步;
第二步: 判断工作队列(workQueue)是否已满,未满则将新的任务提交到工作队列中,满了则进入下一步;
第三步: 判断线程池中的线程数量是否达到了maxumunPoolSize,如果未达到,则新建一个工作线程来执行这个任务,如果达到了则使用饱和策略来处理这个任务。
[
](https://blog.csdn.net/qq_33323054/article/details/106923732)
keepAliveTime
如果一个线程处在空闲状态的时间超过了该属性值,就会因为超时而退出。
举个例子,如果线程池的核心大小corePoolSize=5,而当前大小poolSize =8,那么超出核心大小的线程,会按照keepAliveTime的值判断是否会超时退出。
如果线程池的核心大小corePoolSize=5,而当前大小poolSize =5,那么线程池中所有线程都是核心线程,这个时候线程是否会退出,取决于allowCoreThreadTimeOut。
队列workQueue
缓冲队列有三种通用策略:直接提交、有界队列、无界队列
SynchronousQueue、ArrayBlockingQueue、LinkedBlockingQueue、
SynchronousQueue:
由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加
ArrayBlockingQueue:
有界队列,特点可以防止资源耗尽, 默认有界长度 2147483647(二十一亿 四千七百四十八万多)
LinkedBlockingQueue:
无界队列,会造成资源耗尽
handler 拒绝策略JDK 提供了四种内置拒绝策略,我们要理解并记住,有如下的四种:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 极大概率是main线程去执行
https://www.jianshu.com/p/aa420c7df275
ThreadFactory来定义我们自己的线程工厂,比如说自定义线程名称,组,优先级等信息,可以跟着线程池究竟在何时创建了多少线程等等。
使用Executors 创建线程池
newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
public static void main(String[] args) {
Date time = Calendar.getInstance().getTime();
// Single();
//Scheduled(time);
System.out.println(time);//开始时间
//可缓存的线程池 核心线程数无限大,所以即使线程输出完成 休眠十秒,十个线程也是在一瞬间执行完成的
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
cachedThreadPool.execute(() -> {
System.out.println(Thread.currentThread().getName()+":"+index);
System.out.println(Calendar.getInstance().getTime());
try {
Thread.sleep(10000);//休眠十秒
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
public static void main(String[] args) {
Date time = Calendar.getInstance().getTime();
// Single();
//Scheduled(time);
//CaChed(time);
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
fixedThreadPool.execute(() -> {
try {
System.out.println(Calendar.getInstance().getTime() + ";当前线程名称" + Thread.currentThread().getName());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
/*
Sat Apr 13 11:03:37 CST 2019;当前线程名称pool-1-thread-3
Sat Apr 13 11:03:37 CST 2019;当前线程名称pool-1-thread-2
Sat Apr 13 11:03:37 CST 2019;当前线程名称pool-1-thread-1
Sat Apr 13 11:03:40 CST 2019;当前线程名称pool-1-thread-3
Sat Apr 13 11:03:40 CST 2019;当前线程名称pool-1-thread-2
Sat Apr 13 11:03:40 CST 2019;当前线程名称pool-1-thread-1
Sat Apr 13 11:03:43 CST 2019;当前线程名称pool-1-thread-3
Sat Apr 13 11:03:43 CST 2019;当前线程名称pool-1-thread-2
Sat Apr 13 11:03:43 CST 2019;当前线程名称pool-1-thread-1
Sat Apr 13 11:03:46 CST 2019;当前线程名称pool-1-thread-3
*/
}
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
public static void main(String[] args) {
// Single();
Date time = Calendar.getInstance().getTime();
System.out.println(time);
//核心线程数量 2
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
for (int i = 0; i < 5; i++) {
scheduledThreadPool.schedule(() -> {
System.out.println("三秒后执行,每次间隔两秒" + Calendar.getInstance().getTime() + ";当前线程名称" + Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 3, TimeUnit.SECONDS);
}
/*
Sat Apr 13 10:28:51 CST 2019
三秒后执行,每次间隔两秒Sat Apr 13 10:28:54 CST 2019;当前线程名称pool-1-thread-1
三秒后执行,每次间隔两秒Sat Apr 13 10:28:54 CST 2019;当前线程名称pool-1-thread-2
三秒后执行,每次间隔两秒Sat Apr 13 10:28:56 CST 2019;当前线程名称pool-1-thread-1
三秒后执行,每次间隔两秒Sat Apr 13 10:28:56 CST 2019;当前线程名称pool-1-thread-2
三秒后执行,每次间隔两秒Sat Apr 13 10:28:58 CST 2019;当前线程名称pool-1-thread-2
*/
}
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
public static void main(String[] args) {
//单例的线程
ExecutorService service = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5 ; i++) {
service.execute(() -> {
System.out.println(Thread.currentThread().getName()+ " : " + "查看线程是否是单例的");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
--------------------------------------
pool-1-thread-1 : 查看线程是否是单例的
pool-1-thread-1 : 查看线程是否是单例的
pool-1-thread-1 : 查看线程是否是单例的
pool-1-thread-1 : 查看线程是否是单例的
pool-1-thread-1 : 查看线程是否是单例的
private final BlockingQueue<Runnable> workQueue; // 阻塞队列
private final ReentrantLock mainLock = new ReentrantLock(); // 互斥锁
private final HashSet<Worker> workers = new HashSet<Worker>();// 线程集合.一个Worker对应一个线程
private final Condition termination = mainLock.newCondition();// 终止条件
private int largestPoolSize; // 线程池中线程数量曾经达到过的最大值。
private long completedTaskCount; // 已完成任务数量
private volatile ThreadFactory threadFactory; // ThreadFactory对象,用于创建线程。
private volatile RejectedExecutionHandler handler;// 拒绝策略的处理句柄
private volatile long keepAliveTime; // 线程池维护线程所允许的空闲时间
private volatile boolean allowCoreThreadTimeOut;
private volatile int corePoolSize; // 线程池维护线程的最小数量,哪怕是空闲的
private volatile int maximumPoolSize; // 线程池维护的最大线程数量