一、什么是线程池?
线程池是一种线程的集合,线程池中包含了多个线程,这些线程可以轮流执行池中的任务,从而实现线程的复用,提高系统的效率,避免资源的浪费。线程池具有以下特点:
1、线程可以轮流执行,避免创建或销毁线程的开销
2、线程数量可以控制,防止系统因为线程过多而崩溃
3、线程池中的线程可以自动重用,不需要每次都重新创建线程
4、线程池可以根据不同的任务进行优先级排序,保证高优先级任务先执行
二、创建线程池的步骤
创建线程池的步骤如下:
1、创建一个线程池对象,设置线程池的属性,如核心线程数量、最大线程数量、线程空闲时间、等待队列长度、拒绝策略等等
2、创建一个等待队列,用于存放等待执行的任务
3、创建一个线程池管理器,用于管理线程池的状态,比如线程的创建、销毁、执行任务等
4、向线程池中添加任务,线程池会自动分配线程去执行任务
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThreadPool {
public static void main(String[] args) {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//添加任务到线程池
for(int i=0;i<10;i++){
final int task = i;
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行任务:"+task);
}
});
}
//关闭线程池
executorService.shutdown();
}
}
三、常见的线程池类型
Java中常见的线程池类型有如下几种:
1、FixedThreadPool:固定数量线程池,线程数量一旦设定就不会发生变化。
2、CachedThreadPool:缓存线程池,线程数量可以根据任务的多少自动调整。
3、SingleThreadExecutor:单线程线程池,只有一个线程在执行任务,适合于重要的任务需要顺序执行的场景。
4、ScheduledThreadPool:定时任务线程池,适用于需要按照一定的周期执行任务的场景。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MyScheduledThreadPool {
public static void main(String[] args) {
//创建定时任务线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
//延迟1秒后执行任务
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行任务");
}
},1, TimeUnit.SECONDS);
//每隔2秒执行一次任务
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行任务");
}
}, 0, 2, TimeUnit.SECONDS);
//关闭线程池
scheduledExecutorService.shutdown();
}
}
四、线程池的拒绝策略
当线程池中的线程已经全部被占用,等待队列已经满了,此时如果还有新的任务进来,线程池就需要执行拒绝策略。Java中提供了四种线程池的拒绝策略。
1、AbortPolicy:拒绝新任务并抛出异常
2、CallerRunsPolicy:将新任务提交给调用线程来执行
3、DiscardOldestPolicy:将等待队列中最早的任务丢弃,将新任务添加到等待队列尾部
4、DiscardPolicy:直接丢弃新任务
import java.util.concurrent.*;
public class MyRejectedThreadPool {
static class MyTask implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行任务");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//创建线程池,设置拒绝策略为DiscardPolicy
ExecutorService executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(1), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
//添加任务到线程池
for(int i=0;i<5;i++){
executorService.execute(new MyTask());
}
//关闭线程池
executorService.shutdown();
}
}
五、线程池的最佳实践
1、尽量设置合适的线程数量
线程数量过多会导致系统开销过大,过少会导致系统无法充分利用资源。
2、合理的等待队列长度
等待队列长度过长会导致系统处理速度变慢,过短会导致任务不能得到处理。
3、使用合适的拒绝策略
不同的应用场景需要使用不同的拒绝策略。
4、合理的任务划分与设计
任务应该尽可能合理的拆分,并根据优先级和执行时间进行排序。
六、总结
线程池是一种用于管理线程的机制,具有复用线程、控制线程数量、自动重用、以及优先级等特点,可以提高系统效率,避免资源浪费。在使用线程池时,要注意线程池的属性设置、拒绝策略的选择、以及任务的合理划分与设计,从而达到最佳的效果。
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/179903.html
微信扫一扫
支付宝扫一扫