由浅及深认识线程池

一:线程池介绍
1.1 概念

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程

1.2 工作机制

CPU将任务提交给线程池,线程池拿到任务后,在内部寻找空闲的线程来处理任务

1.3 使用原因

多线程运行时,频繁的进行线程的创建和销毁,会过度的消耗系统资源,增加并发变成风险

1.4 组成部分
  • 线程池管理器(ThreadPoolManage):用来创建并管理线程池

  • 工作线程(workThread):线程池中的线程

  • 任务队列(Queue):用于存放没有处理好的任务,提供一种缓冲机制

  • 任务接口(Task):每个任务必须实现的接口 ,以供工作线程调度任务的执行

1.5 作用
  • 利用线程池管理并复用线程、控制最大并发数等
  • 实现任务线程队列缓存策略和拒绝机制
  • 实现某些与时间相关的功能,如定时执行、周期执行
  • 隔离线程环境。当不同服务之间资源消耗相差过大时,配置独立的线程池,可以避免各服务线程相互影响
1.6 执行过程

在这里插入图片描述

二:四种常见的线程池

线程工厂Executors实现的种类

实现名称使用的队列说明
FixedThreadPool固定大小线程池LinkedBlockingQueue固定线程数量,不存在空闲线程,任务队列无界
WorkStealingPool并行线程池FIFO_QUEUE线程数量不限制,使用ForkJoinPool分治法来执行任务
CachedThreadPool缓冲线程池SynchronousQueue核心线程数为0,最大线程数量为Integer.MAX_VALUE,自己根据cpu性能决定线程数量
ScheduledThreadPool定时任务线程池DelayedWorkQueue最大线程数量为Integer.MAX_VALUE,任务按时间优先级执行,不回收工作线程
SingleThreadExecutor单线程线程池LinkedBlockingQueue线程数量1个,任务按加入顺序执行
补充
队列说明
LinkedBlockingQueue基于链表和显示锁实现的队列
SynchronousQueue基于双栈/双队列和显示锁实现的交付队列
DelayedWorkQueue基于优先级队列和显示锁实现的延迟队列,按照执行时间的升序来排序,执行时间举例当前时间越近的任务在队列前面
2.1 newSingleThreadExecutor
2.1.1 使用的小例子
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author miao
 */
public class ThreadPoolExecutorDemo {

    public static void main(String[] args) {

        ExecutorService singleThread = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 3;i++){
            int finalI = i;

            singleThread.execute(()->{

                try {

                    System.out.println(finalI);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            });
        }
    }
}
2.1.2 源码阅读

在这里插入图片描述

总结

newSingleThreadExecutor的核心线程数和最大线程数都是1,所以该线程池中只有一个线程执行任务,而队列使用的是无界队列LinkedBlockingQueue(队列的容量为Integer.MAX_VALUE),可能会造成OOM异常

2.2 newCachedThreadPool
2.2.1 使用的小例子
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author miao
 */
public class ThreadPoolExecutorDemo {

    public static void main(String[] args) {

        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

        for (int i = 0; i < 3;i++){

            int finalI = i;
            cachedThreadPool.execute(()->{

                try {

                    System.out.println(finalI);
                    Thread.sleep(10000);
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            });
        }
    }
}
2.2.2 阅读源码

在这里插入图片描述

总结

newCachedThreadPool 核心线程数为0,最大线程数为Integer.MAX_VALUE,简单来说就是遇强则强 自己根据cpu性能决定线程数量

2.3 newFixedThreadPool
2.3.1 使用的小例子
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author miao
 */
public class ThreadPoolExecutorDemo {

    private static final int THREAD_COUNT = 3;

    public static void main(String[] args) {

        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(THREAD_COUNT);

        for (int i = 0; i < 6; i++) {

            int finalI = i;
            fixedThreadPool.execute(() -> {

                try {

                    System.out.println(finalI);
                    Thread.sleep(10000);
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            });
        }
    }
}
2.3.2 阅读源码在这里插入图片描述
总结
固定线程池 默认活跃线程数,最大线程数都为方法形参,这里把keepAliveTime设置为0L,意味着多余的空闲线程会被立即终止,而队列使用的是无界队列LinkedBlockingQueue(队列的容量为Integer.MAX_VALUE),可能会造成OOM异常
2.4 newScheduledThreadPool
2.4.1 使用的小例子
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author miao
 */
public class ThreadPoolExecutorDemo {

    private static final int THREAD_COUNT = 3;

    public static void main(String[] args) {

        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(THREAD_COUNT);
        scheduledThreadPool.schedule(
                () -> System.out.println("延迟三秒执行"), 
                3, 
                TimeUnit.SECONDS);
    }
}
2.4.2 阅读源码

由于ScheduleThreadPoolExecutor继承了ThreadPoolExecutor,所以线程池的实现还是父类的构造方法

在这里插入图片描述

总结

ScheduledThreadPoolExecutor主要用来在给定的延迟之后运行任务,或者定期执行任务,它的功能与Timer类似,但却更强大,更灵活。Timer对应的是单个后台线程,而ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数

三:ThreadPoolExecutor

其实这四种线程池最终的实现方式都是ThreadPoolExecutor的构造方法
在这里插入图片描述

下面对参数进行说明
参数解释
corePoolSize常驻核心线程数。如果等于0,则任务执行完后没有任何请求进入时销毁线程池的线程;如果大于0,及时本地任务执行完毕,核心线程也不会被销毁
maximumPoolSize表示线程池能够容纳同时执行的最大线程数,必须大于等于1。如果当阻塞队列已满时,并且当前线程池线程个数没有超过 maximumPoolSize 的话,就会创建新的线程来执行任务。
keepAliveTime空闲线程存活时间。如果当前线程池的线程个数已经超过了 corePoolSize,并且线程空闲时间超过了 keepAliveTime 的话,就会将这些空闲线程销毁,直到只剩下corePoolSize个线程为止,但是当ThreadPoolExecutorallowCoreThreadTimeOut设置为true时,核心线程超时后也会被回收
unit时间单位。为 keepAliveTime 指定时间单位,通常为 TimeUnit.SECONDS
workQueue阻塞队列,用于保存任务。可以使用 ArrayBlockingQueue, LinkedBlockingQueue, SynchronousQueue, PriorityBlockingQueue
threadFactory线程工厂,用来生成一组相同任务的线程。线程池的命令是通过这个factory增加组名前缀来实现的,在虚拟机分析时,就可以直到线程任务是由哪个线程工厂产生的
handler执行拒绝策略的对象。当线程池的阻塞队列已满和指定的线程都已经开启,说明当前线程池已经处于饱和状态了,那么就需要采用一种策略来处理这种情况
1. AbortPolicy(用的最多):直接拒绝所提交的任务,并抛出RejectedExecutionException异常
2. CallerRunsPolicy:只用调用者所在的线程来执行任务
3. DiscardPolicy:不处理直接丢弃掉任务
4. DiscardOldestPolicy:丢弃掉阻塞队列中存放时间最久的任务,执行当前任务
下一篇 自定义线程工厂与拒绝策略的实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值