一、说明
线程池的引出
通过 new 语句创建一个 Java 对象时,JVM 就会为这个对象分配一块内存空间
而线程的创建和销毁需要调用操作系统内核的 API,成本较高
线程池是一个容纳多个线程的容器,通过复用线程来达到执行多个任务的目的,对线程进行统一的分配,调优和监控,无需重复创建线程,优化了资源开销,由此引出Executor
框架
二、理解
Executor
包括三大部分
任务:被执行任务需要实现Callable
和 Runnable
接口
任务的执行:把任务分派给多个线程的执行机制, Executor
和ExecutorService
接口及其实现类
异步计算的结果: Future
接口 FutureTask
实现类
Executor
即线程池接口,其execute()
方法接收Runnable
接口的对象,但没有返回结果
ExecutorService
接口用来实现和管理多线程,提供生命周期管理方法,返回 Future 对象,当所有已经提交的任务执行完毕后将会关闭该接口
AbstractExecutorService
类用来提供线程接口的一些默认实现
ThreadPoolExecutor
线程池的实现类,通过调用 Executors 创建线程池并返回一个 ExecutorService 对象
ScheduledExecutorService
接口用来执行定时任务
ScheduledThreadPoolExecutor
用来调度定时任务的线程池实现类
Executor 框架使用流程
ExecutorService
Executors
线程池工厂类,提供生成 Executor(线程池)的方法,返回的线程池都实现了ExecutorService
接口
newSingleThreadExecutor()
创建单个线程的线程池
newFixedThreadPool(int numOfThreads)
创建固定线程数的线程池,可控制线程最大并发数,超出的线程会在队列中等待
newCachedThreadPool()
根据需要创建新的线程,自动回收空闲线程,所有线程都会在限制 60 秒后被回收,如果回收后又创建了任务,将新创建一个线程
newScheduledThreadPool(int)
创建一个支持定时及周期性执行任务的线程池
三、实现
1. newSingleThreadExecutor
创建一个SingThreadExecutorTest
类,单个线程的线程池执行MyThread1
和MyThread2
任务
public class SingThreadExecutorTest {
public static void main(String[] args) {
// 1.创建一个单线程化的线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
// 2.创建10次线程任务
for (int i = 0; i < 5; i++) {
// 3.执行线程任务
executorService.execute(new MyThread1());
executorService.execute(new MyThread2());
}
// 4.关闭线程池
executorService.shutdown();
}
static class MyThread1 extends Thread {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 我是任务1");
sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
static class MyThread2 extends Thread {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 我是任务2");
sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
复制代码
只有单个线程池去执行 10 个任务
2. newFixedThreadPool
创建固定线程数的线程池,可控制线程最大并发数,超出的线程会在队列中等待
public static void main(String[] args) {
// 1.创建容量为5线程数的线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
// 2.创建10次线程任务
for (int i = 0; i < 5; i++) {
// 3.执行线程任务
executorService.execute(new MyThread1());
executorService.execute(new MyThread2());
}
// 4.关闭线程池
executorService.shutdown();
}
复制代码
5 个线程去执行 10 个任务
3. newCachedThreadPool
根据需要创建新的线程,自动回收空闲线程,所有线程都会在限制 60 秒后被回收,如果回收后又创建了任务,将新创建一个线程
public static void main(String[] args) {
// 1.创建可缓存的线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 2.创建10次线程任务
for (int i = 0; i < 5; i++) {
// 3.执行线程任务
executorService.execute(new MyThread1());
executorService.execute(new MyThread2());
}
// 4.关闭线程池
executorService.shutdown();
}
复制代码
根据需要自动创建新线程去只执行 10 个任务
当线程运行时间超过 60 秒时
public static void main(String[] args) throws InterruptedException {
// 1.创建可缓存的线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 2.创建线程任务执行
for (int i = 0; i < 5; i++) {
executorService.execute(new MyThread1());
}
Thread.sleep(30000);
System.out.println("睡眠30秒");
for (int i = 0; i < 5; i++) {
executorService.execute(new MyThread1());
}
Thread.sleep(65000);
System.out.println("睡眠65秒");
for (int i = 0; i < 5; i++) {
executorService.execute(new MyThread1());
}
// 4.关闭线程池
executorService.shutdown();
}
复制代码
5 个线程执行任务再休眠 30 秒后,线程并未被回收,继续用这 5 个线程执行任务,休眠 65 秒后,线程被回收,新建 5 个线程执行任务
4. newScheduledThreadPool
创建一个支持定时及周期性执行任务的线程池
public class SingThreadExecutorTest {
public static void main(String[] args) {
// 1.创建容量为5线程数的线程池
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
// 2.创建10次线程任务
for (int i = 0; i < 5; i++) {
// 3.执行线程任务
executorService.schedule(new MyThread1(),5000 , TimeUnit.MILLISECONDS);
executorService.schedule(new MyThread2(),1000 , TimeUnit.MILLISECONDS);
}
复制代码
5 个线程去执行 10 个任务,任务 2 马上就执行完成了,而任务 1 要延迟 5 秒才执行完成
评论