一、线程池的优势
1.降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗。
2.提高系统相应速度,当有任务到达时,通过复用已存在的行程,无需等待新线程的创建便能立刻执行。
3.方便线程并发数的管控,因为线程若是无限制创建,可能会导致内存占用过多而产生内存溢出,并且会造成cpu过度切换。
4.提供更强大的功能,延时定时线程池。
二、线程池的种类
Executors类提供了4种不同的线程池:newCachedThreadPool, newFixedThreadPool, newScheduledThreadPool, newSingleThreadExecutor。
1.newCachedThreadPool:用来创建一个可以无限扩大到线程池,适用于负载较轻的场景,执行短期异步任务。
2.newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。
3.newScheduledThreadPool:适用于执行延时或周期性的任务。
4.newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务。
三、线程池的测试
先创建一个自定义的线程类
示例代码如下:
import java.util.Date;
/**
* @author qinxun
* @date 2023-06-13
* @Descripion: 自定义线程类
*/
public class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name + "->start time:" + new Date());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(name + "->end time:" + new Date());
}
}
1.使用newCachedThreadPool创建可缓存的线程池
示例代码如下:
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author qinxun
* @date 2023-06-13
* @Descripion: 线程池测试
*/
public class ExecutorsDemo {
public static void main(String[] args) {
// 可缓存的线程池
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
MyRunnable runnable = new MyRunnable(String.valueOf(i));
executorService.execute(runnable);
}
executorService.shutdown();
System.out.println("Main Thread:Finished at:" + new Date());
}
}
程序执行结果:
0->start time:Tue Jun 13 15:18:31 CST 2023
4->start time:Tue Jun 13 15:18:31 CST 2023
2->start time:Tue Jun 13 15:18:31 CST 2023
3->start time:Tue Jun 13 15:18:31 CST 2023
1->start time:Tue Jun 13 15:18:31 CST 2023
Main Thread:Finished at:Tue Jun 13 15:18:31 CST 2023
4->end time:Tue Jun 13 15:18:31 CST 2023
3->end time:Tue Jun 13 15:18:31 CST 2023
1->end time:Tue Jun 13 15:18:31 CST 2023
0->end time:Tue Jun 13 15:18:31 CST 2023
2->end time:Tue Jun 13 15:18:31 CST 2023
根据需要创建自定义数量的线程。
2.使用newFixedThreadPool创建固定长度的线程池。
示例代码如下:
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author qinxun
* @date 2023-06-13
* @Descripion: 线程池测试
*/
public class ExecutorsDemo {
public static void main(String[] args) {
// 创建固定长度的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
MyRunnable runnable = new MyRunnable(String.valueOf(i));
executorService.execute(runnable);
}
executorService.shutdown();
System.out.println("Main Thread:Finished at:" + new Date());
}
}
程序执行结果:
Main Thread:Finished at:Tue Jun 13 15:23:03 CST 2023
0->start time:Tue Jun 13 15:23:03 CST 2023
2->start time:Tue Jun 13 15:23:03 CST 2023
1->start time:Tue Jun 13 15:23:03 CST 2023
0->end time:Tue Jun 13 15:23:03 CST 2023
1->end time:Tue Jun 13 15:23:03 CST 2023
2->end time:Tue Jun 13 15:23:03 CST 2023
4->start time:Tue Jun 13 15:23:03 CST 2023
3->start time:Tue Jun 13 15:23:03 CST 2023
4->end time:Tue Jun 13 15:23:03 CST 2023
3->end time:Tue Jun 13 15:23:03 CST 2023
我们发现前面固定的3个线程先执行,后续创建新的线程来执行任务。
3.使用newSingleThreadExecutor创建单线程线程池
示例代码如下:
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author qinxun
* @date 2023-06-13
* @Descripion: 线程池测试
*/
public class ExecutorsDemo {
public static void main(String[] args) {
// 创建单线程线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
MyRunnable runnable = new MyRunnable(String.valueOf(i));
executorService.execute(runnable);
}
executorService.shutdown();
System.out.println("Main Thread:Finished at:" + new Date());
}
}
程序执行结果:
Main Thread:Finished at:Tue Jun 13 15:27:15 CST 2023
0->start time:Tue Jun 13 15:27:15 CST 2023
0->end time:Tue Jun 13 15:27:15 CST 2023
1->start time:Tue Jun 13 15:27:15 CST 2023
1->end time:Tue Jun 13 15:27:15 CST 2023
2->start time:Tue Jun 13 15:27:15 CST 2023
2->end time:Tue Jun 13 15:27:15 CST 2023
3->start time:Tue Jun 13 15:27:15 CST 2023
3->end time:Tue Jun 13 15:27:15 CST 2023
4->start time:Tue Jun 13 15:27:15 CST 2023
4->end time:Tue Jun 13 15:27:15 CST 2023
我们发现当前的线程是一个个顺序执行的。
4.使用newScheduledThreadPool实现延迟或定时的线程池
scheduleAtFixedRate:按指定频率周期执行某个任务,是以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行。
scheduleWithFixedDelay:周期定时执行某个任务/按指定频率间隔执行某个任务(注意)是以上一个任务结束时开始计时,period时间过去后,立即执行。
示例代码如下:
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author qinxun
* @date 2023-06-13
* @Descripion: 线程池测试
*/
public class ExecutorsDemo {
public static void main(String[] args) {
// 创建单线程线程池
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 5; i++) {
MyRunnable runnable = new MyRunnable(String.valueOf(i));
// 延迟1秒,每隔3秒执行一遍(上一个任务结束开始计时)
executorService.scheduleAtFixedRate(runnable, 1, 3, TimeUnit.SECONDS);
}
//executorService.shutdown();
System.out.println("Main Thread:Finished at:" + new Date());
}
}
程序执行结果:
Main Thread:Finished at:Tue Jun 13 15:44:10 CST 2023
0->start time:Tue Jun 13 15:44:11 CST 2023
2->start time:Tue Jun 13 15:44:11 CST 2023
1->start time:Tue Jun 13 15:44:11 CST 2023
0->end time:Tue Jun 13 15:44:11 CST 2023
2->end time:Tue Jun 13 15:44:11 CST 2023
3->start time:Tue Jun 13 15:44:11 CST 2023
1->end time:Tue Jun 13 15:44:11 CST 2023
4->start time:Tue Jun 13 15:44:11 CST 2023
4->end time:Tue Jun 13 15:44:12 CST 2023
3->end time:Tue Jun 13 15:44:12 CST 2023
0->start time:Tue Jun 13 15:44:14 CST 2023
2->start time:Tue Jun 13 15:44:14 CST 2023
1->start time:Tue Jun 13 15:44:14 CST 2023
1->end time:Tue Jun 13 15:44:14 CST 2023
0->end time:Tue Jun 13 15:44:14 CST 2023
2->end time:Tue Jun 13 15:44:14 CST 2023
4->start time:Tue Jun 13 15:44:14 CST 2023
3->start time:Tue Jun 13 15:44:14 CST 2023