线程池是一种线程管理的机制,它是一组线程的集合,可以用来执行多个任务。线程池维护了一个固定数量的线程集合,可以从线程池中取出一个线程来执行任务,当任务执行完毕后,线程又会返回到线程池中,等待下一个任务的到来。当所有线程都处于忙碌状态时,线程池会创建一个新的线程进行处理,如果超过线程最大数,则进入等待队列,进行等待。
2.线程池的优点
资源控制:线程池可以限制线程数量,避免线程过多导致系统资源不足。
提高响应速度:线程池中的线程已经预先创建,可以避免线程创建时的开销,从而可以更快地响应请求。
提高系统稳定性:线程池可以避免系统过载,从而提高系统的稳定性和可靠性。
提高资源利用率:线程池中的线程可以重复利用,避免了线程的频繁创建和销毁,从而提高了资源的利用率。
public class Test01 {
public static void main(String[] args) throws InterruptedException {
//创建固定数目的线程池
ExecutorService executorService=Executors.newFixedThreadPool(4);
//提交六个线程任务
for(int i=0;i<6;i++) {
executorService.execute(new Task("线程"+i));
}
executorService.shutdown();
while(!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
System.out.println("线程池暂未关闭!");
}
System.out.println("线程池已经关闭!");
}
}
public class Test02 {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService=Executors.newCachedThreadPool();
//提交六个线程任务
for(int i=0;i<60;i++) {
executorService.execute(new Task("线程"+i));
}
executorService.shutdown();
while(!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
System.out.println("线程池暂未关闭!");
}
System.out.println("线程池已经关闭!");
}
}
//周期性执行线程任务
public class Test04 {
public static void main(String[] args) {
ScheduledExecutorService executorService=Executors.newScheduledThreadPool(3);
//延迟3秒钟执行任务执行一次
// System.out.println("当前时间:"+LocalDateTime.now());
// executorService.schedule(new Task("任务A"), 3, TimeUnit.SECONDS);
//延迟一秒钟后执行任务,每隔3秒钟执行一次
// System.out.println("当前时间:"+LocalDateTime.now());
// executorService.scheduleAtFixedRate(new Task("任务A"), 1, 3, TimeUnit.SECONDS);
System.out.println("当前时间:"+LocalDateTime.now());
executorService.scheduleWithFixedDelay(new Task("任务A"), 1, 3, TimeUnit.SECONDS);
}
}
常见的阻塞队列
- ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
- LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
- SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
- PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
- DelayedWorkQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
public class Test05 {
public static void main(String[] args) {
ExecutorService executorService=new ThreadPoolExecutor(10, 11, 1, TimeUnit.SECONDS,
new LinkedBlockingDeque(),
new MyThreadFactory());
//提交六个线程任务
for(int i=0;i<60;i++) {
executorService.execute(new Task("线程"+i));
}
}
}
public class MyThreadFactory implements ThreadFactory {
private final AtomicInteger number=new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
Thread t=new Thread(r);
t.setName("订单线程"+number.incrementAndGet());
return t;
}
}
class Task implements Runnable{
private String TaskName;
public Task(String taskName) {
this.TaskName = taskName;
}
@Override
public void run() {
System.out.println("启动线程===>"+this.TaskName);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束线程===>"+this.TaskName);
}
}
1.接口/类:
ExecutorService接口:进行线程池的操作访问。
Executors类:创建线程池的工具类。
ThreadPoolExecutor及其子类:封装线程池的核心参数和运行机制。
2.执行线程任务
awaitTermination(long timeout,TimeUnit unit) :每间隔一定时间检查一次线程执行任务状态,等待线程池关闭。
public class Test01 {
public static void main(String[] args) {
//创建1-100w之间的多有数字累加和,每10W个数字交给一个线程处理
//创建一个固定大小的线程池
ExecutorService executorService=Executors.newFixedThreadPool(4);
//创建集合用于保存Future执行结果
List> futureList=new ArrayList>();
//每10w个数字封装成一个callable线性任务,并提交给线程池
for(int i=0;i<900000;i+=100000) {
Future total=executorService.submit(new CalcTask(i, i+100000));
futureList.add(total);
}
try {
int total=0;
for(int i=0;i{
private int begin,end;
public CalcTask(int begin,int end) {
this.begin=begin;
this.end=end;
}
@Override
public Integer call() throws Exception {
int total=0;
for(int i=begin;i<=end;i++) {
total+=i;
}
System.out.printf("线程%s计算%d-%d范围的任务结束!\n",Thread.currentThread().getName(),begin,end);
return total;
}
}
线程的关闭
shutdown():关闭线程池,但会等正在执行任务的线程结束再关闭。
shutdownNow():立即关闭。
线程池中的线程数量是有限的,每个线程可以处理多个任务。线程池的工作原理主要分为以下几个步骤:
拒绝策略
常见的线程池拒绝策略有:
CallerRunsPolicy:由调用线程处理该任务,即在提交任务的线程中执行该任务,谁调用谁处理。
AbortPolicy:直接抛出异常,阻止系统正常工作。
DiscardPolicy:直接丢弃任务,不进行处理。
DiscardOldestPolicy:丢弃队列中最旧的任务,尝试为当前任务腾出位置。
线程池的状态分为:running, shutdown,stop,tidying,terminated。
running
shutdown
stop
tidying
terminated