Java学习笔记5线程池
Java学习笔记5-线程池
线程池原理 - 我的理解就是个送快递的网点
- 线程池管理器:用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务;- 快递网点管理者,可以招聘和辞退快递小哥,收件分件等
- 工作线程:线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;- 送快递的小哥
- 任务接口:每个任务必须实现的接口,以供工作线程调度任务的执行,他主要规定了任务的入口,任务执行完成后的收尾工作,任务的执行状态等;- 快递包裹的规格,快递单及配送信息等,没地址的快递小哥可没法送
- 任务队列:用于存放没有处理的任务。提供一种缓冲机制。- 存放快递包裹的仓库
线程池API
Executor(接口):最上层的接口,定义了执行任务的方法execute
ExecutorService(接口):继承Executor接口,扩展了Callable、Future、关闭方法
ScheduledExecutorService(接口):继承ExecutorService接口,增加了定时任务相关方法
ThreadPoolExecutor(实现类):基础、标准的线程池实现,推荐使用,创建线程达到核心线程数 -> 再将任务队列放满 -> 可创建线程达到最大线程数 -> 执行拒绝策略
public ThreadPoolExecutor(int corePoolSize, // 核心线程数量
int maximumPoolSize, // 最大线程数量
long keepAliveTime, // 超出核心线程数量的线程空闲存活时间
TimeUnit unit, // 存活时间单位
BlockingQueue<Runnable> workQueue, // 等待任务队列
ThreadFactory threadFactory, // 线程创建工厂,可选
RejectedExecutionHandler handler // 指定拒绝策略的,可选
) {
// ...
}
ThreadPoolExecutor测试代码
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Author: Wenx
* @Description:
* @Date: Created in 2019/11/11 17:14
* @Modified By:
*/
public class DemoTest {
public static void main(String[] args) throws InterruptedException {
// 创建一个 核心线程数量为2,最大线程数量为5,等待队列为3 的线程池,相当于最大容纳8个任务
// 默认的策略是抛出RejectedExecutionException异常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2, 5, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(3),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("快递网点:快递小哥不够仓库已满 / 停止业务 -> 拒收快递包裹");
}
});
// 测试: 提交 10个 执行时间需要3秒的任务,看超过2个任务时的对应处理情况
int num = 10;
for (int i = 0; i < num; i++) {
int n = i + 1;
System.out.println("快递包裹" + n + ":到达快递网点");
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println("------------------------------快递小哥正在送 快递包裹" + n);
Thread.sleep(3000L);
System.out.println("------------------------------快递包裹" + n + " 已送达");
} catch (InterruptedException e) {
System.err.println("------------------------------快递小哥翻车了:" + e.getMessage());
}
}
});
System.out.println("派件快递小哥人数为:" + threadPoolExecutor.getPoolSize());
System.out.println("网点仓库包裹数量为:" + threadPoolExecutor.getQueue().size());
}
// 8秒后快递包裹应该都配送完了(具体延迟时间可以调整至都配送完,还有5人=2核心+3临时)
Thread.sleep(8000L);
System.out.println("快递网点:快递包裹应该差不多配送完了");
System.out.println("派件快递小哥人数为:" + threadPoolExecutor.getPoolSize());
System.out.println("网点仓库包裹数量为:" + threadPoolExecutor.getQueue().size());
// 没活干5秒的临时快递小哥要被辞退了(空闲5秒就要被辞退,就剩核心2人)
Thread.sleep(5000L);
System.out.println("快递网点:没活干5秒的临时快递小哥要被辞退");
System.out.println("派件快递小哥人数为:" + threadPoolExecutor.getPoolSize());
System.out.println("网点仓库包裹数量为:" + threadPoolExecutor.getQueue().size());
threadPoolExecutor.shutdown(); // 快递网点停止业务,但现有快递包裹还会配送
//threadPoolExecutor.shutdownNow(); // 快递网点停止业务,现有快递包裹也不会配送
System.out.println("快递网点:停止业务");
Thread.sleep(1000L);
System.out.println("派件快递小哥人数为:" + threadPoolExecutor.getPoolSize());
System.out.println("网点仓库包裹数量为:" + threadPoolExecutor.getQueue().size());
// 再次提交提示失败
System.out.println("快递包裹" + (num + 1) + ":到达快递网点");
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println("又来一个快递包裹");
}
});
// 结果分析
// 1、 2个任务(快递包裹)直接分配线程(快递小哥)开始执行(配送)
// 2、 3个任务(快递包裹)进入等待队列(快递网点仓库)
// 3、 队列(仓库)不够用,临时加开3个线程(快递小哥)来执行任务(5秒没活干就辞退)
// 4、 队列(仓库)和线程池(快递小哥)都满了,剩下2个任务(快递包裹),没资源了,被拒绝执行(拒收)。
// 5、 等待现有任务执行结束(配送完),应当还有5个任务(5人=2核心+3临时)
// 6、 5秒后,如果无任务可执行(没活干),销毁临时创建的3个线程(辞退临时快递小哥)
// 7、 调用shutdown(停止业务),不接收新的任务(快递包裹)
// 8、 在线程池关闭(停止业务)后追加的任务(快递包裹),无法再提交,会被拒绝执行(拒收)
}
}
ScheduledThreadPoolExecutor(实现类):定时任务线程池实现,继承了ThreadPoolExecutor,实现了ScheduledExecutorService中定时任务相关的方法
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, // 核心线程数量
Integer.MAX_VALUE, // 最大线程数量
0, // 超出核心线程数量的线程空闲存活时间
NANOSECONDS, // 存活时间单位
new DelayedWorkQueue() // 等待任务队列-延时队列,没有到达时间取不出来
);
}
ScheduledThreadPoolExecutor测试代码
import java.text.SimpleDateFormat;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Author: Wenx
* @Description:
* @Date: Created in 2019/11/11 17:14
* @Modified By:
*/
public class DemoTest {
public static void main(String[] args) throws InterruptedException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
// 定时3秒后执行一次任务
threadPoolExecutor.schedule(new Runnable() {
@Override
public void run() {
System.out.println("定时任务1 开始执行,当前时间为:" + dateFormat.format(System.currentTimeMillis()));
}
}, 3000, TimeUnit.MILLISECONDS);
System.out.println("定时任务1 提交成功,当前时间为:" + dateFormat.format(System.currentTimeMillis()));
System.out.println("当前线程池中线程数量:" + threadPoolExecutor.getPoolSize());
// 周期性执行任务
// scheduleAtFixedRate:2秒后执行第一次任务,之后每间隔1秒执行一次(如果上次执行还未结束,则等待结束后立刻执行)
threadPoolExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("定时任务2 开始执行,当前时间为:" + dateFormat.format(System.currentTimeMillis()));
}
}, 2000, 1000, TimeUnit.MILLISECONDS);
System.out.println("定时任务2 提交成功,当前时间为:" + dateFormat.format(System.currentTimeMillis()));
System.out.println("当前线程池中线程数量:" + threadPoolExecutor.getPoolSize());
// scheduleWithFixedDelay:2秒后执行第一次任务,之后每间隔1秒执行一次(如果上次执行还未结束,则等待结束后,再等待1秒执行)
threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("定时任务3 开始执行,当前时间为:" + dateFormat.format(System.currentTimeMillis()));
}
}, 2000, 1000, TimeUnit.MILLISECONDS);
System.out.println("定时任务3 提交成功,当前时间为:" + dateFormat.format(System.currentTimeMillis()));
System.out.println("当前线程池中线程数量:" + threadPoolExecutor.getPoolSize());
}
}
Executors(工具类):创建线程池工厂类,不推荐使用,因为创建的都是无界队列线程池,线程处理不完的话,队列有多少收多少,推荐直接使用ThreadPoolExecutor配置有界队列
newFixedThreadPool(int nThreads):创建一个固定大小的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newCachedThreadPool():创建一个缓冲线程池,可以动态调整线程池大小
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newSingleThreadExecutor():创建一个单一线程池
public static ExecutorService newSingleThreadExecutor() {
return new Executors.FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newScheduledThreadPool(int corePoolSize):创建一个定时执行任务的线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
以上是 Java学习笔记5线程池 的全部内容, 来源链接: utcz.com/z/511200.html