我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是会有一个问题:
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率。
那么有没有一种办法使得线程可以复用,执行完一个任务,并不被销毁,而是可以继续执行其他任务。
在Java中通过线程池达到这样的效果,java.util.concurrent.ThreadPoolExcutor类时线程池中最核心的一个类
并发API引入了ExecutorService作为一个在程序中直接使用Thread的高层次替换方案。Executors支持运行异步任务,通常管理一个线程池,这样一来我们就不需要手动去创建新线程。在不断处理任务的过程中,线程池内部线程将会得到复用,因此,我们可以使用一个executorService来运行整个程序中需要并发执行的任务。
Executors类提供了便利的工厂方法来创建不同类型的executorService。
Executors必须显式地停止,否则将持续监听新的任务,executorService提供了两个方法:
- shutdown() 等待正在执行的任务执行完
- shutdownNow() 终止所有正在执行的任务并立即关闭
package com.test.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadPoolTest {
public static void main(String[] args) {
// 1. 线程池 :作用提高线程对象的复用性
// 2. 创建线程池
// 2.1 创建一个单一的线程对象的线程池对象 只管理一个线程对象
// ExecutorService service = Executors.newSingleThreadExecutor();
// 2.2创建一个可以创建多个线程对象的线程池 如果有现成的线程对象 直接用,没有的话创建新的
// 如果一个线程对象60s钟没用被使用,则将其对象移除
// ExecutorService service = Executors.newCachedThreadPool();
// 2.3 创建一个固定线程对象的线程池
ExecutorService service = Executors.newFixedThreadPool(2);
// 创建任务对象
Runnable task1 = new Runnable() {
@Override
public void run() {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"--->task 1 "+i);
}
}
};
Runnable task2 = new Runnable() {
@Override
public void run() {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"--->task 2 "+i);
}
}
};
// 提交一个任务
service.submit(task1);
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
service.submit(task2);
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
service.submit(task1);
// service.submit(task2);
//
// 3. 退出程序
service.shutdown(); // 会将之前要已经提交过的 任务全部执行完成之后 关闭程序 之后再提交的任务会被拒绝
// service.submit(task1);
try {
// 阻塞方法 在shutdown方法调用后调用该方法 直到线程池中的任务执行完成或者时间超时之后执行之后的代码
// 返回值true 表示所有任务执行完成 false表示超时,有部分任务没有执行完
boolean b = service.awaitTermination(200, TimeUnit.SECONDS);
System.out.println(b);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}