• 线程池 的一些事


    目录

    一、线程池

    1. 线程池的好处?

    1. ThreadPoolExecutor 和 Executor ?

    二、构造方法:

    1. ThreadPoolExecutor提供了四个构造方法:

     2. 构造参数解释:

    3. 线程池的执行流程

    4. 几种拒绝策略

    5. 由于参数过于复杂,我们可以通过Executors的工厂方法创建线程池

    三、代码简单实现


     

     

    一、线程池

    1. 线程池的好处?

    创建线程:线程的本质是PCB,是内核中的数据结构。而创建线程,由内核完成 PCB 的创建,把PCB加入到调度队列中~~然后再返回给应用程序。

    而加入线程池:从线程池中去线程,把线程放回到线程池,这是纯用户态实现的逻辑。

    创建线程需要涉及到 用户态~内核态 之间的切换,而这种切换存在很大的开销。为了避免这种情况,引入了线程池,实现了 纯用户态 的逻辑。

    1. ThreadPoolExecutor 和 Executor ?

    在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用 Executor 去创建,而要通过 ThreadPoolExecutor 方式,这一方面是由于 jdk 中  Executor  框架虽然提供了如newFixedThreadPool()newSingleThreadExecutor()newCachedThreadPool()创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor 方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。

    •  Executor 类 本质上是ThreadPoolExecutor 类 的封装
    • 说白了,使用 Executor 类创建线程池与使用ThreadPoolExecutor类的区别就是使用 ThreadPoolExecutor 类可以自定义传入我们设置的线程池的参数,更加灵活。

     

    二、构造方法:

    1. ThreadPoolExecutor提供了四个构造方法:

     

     2. 构造参数解释:

    序号名称类型含义
    1corePoolSizeint核心线程池大小
    2maximumPoolSizeint最大线程池大小
    3keepAliveTimelong线程最大空闲时间
    4unitTimeUnit时间单位
    5workQueueBlockingQueue线程等待队列
    6threadFactoryThreadFactory线程创建工厂
    7handlerRejectedExecutionHandler拒绝策略

     

    3. 线程池的执行流程

    ① 当加入一个新任务时,判断 当前线程数 > 核心线程数 ? 如果false,则新建线程并且执行任务。

    ② 如果true,则判断 任务队列是否满了? 如果false,则放到任务队列,等待核心线程处理。

    ③ 如果true,则判断 当前线程数>最大线程数? 如果false 则新建线程执行此任务。

    ④ 如果true,则执行拒绝策略

    4. 几种拒绝策略

    AbortPolicy         -- 抛出 RejectedExecutionException 异常。
    CallerRunsPolicy    -- 让调用者处理
    DiscardOldestPolicy -- 丢弃最老的任务,将新任务放到等待队列。
    DiscardPolicy       -- 直接丢弃这个新任务

    5. 由于参数过于复杂,我们可以通过Executors的工厂方法创建线程池

    1. newFixedThreadPool :创建固定线程数的线程池
    2. CachedThreadPool:创建线程数媒动态增长的线程池
    3. SingleThreadExecutor:创建只包含单个线程的线程池
    4. ScheduledThreadPool:设定 延迟时间后执行命令,或定期执行命令,是进阶版的 Timer
    1. public static void main(String[] args) {
    2. //创建一个固定有10个线程数的线程池
    3. ExecutorService executorService = Executors.newFixedThreadPool(10);
    4. Runnable run = new Runnable() {
    5. @Override
    6. public void run() {
    7. System.out.println("good !");
    8. }
    9. };
    10. executorService.submit(run);
    11. }

    三、代码简单实现

    • 核心操作是 submit --- 将任务加入到线程池中
    • 使用 Worker 类描述一个工作线程,使用 Runnable 或者 Callable 描述一个任务
    • 使用一个 BlockingQueue 组织所有任务
    • 每个Worker 县城要做的事情:不停的从 BlockingQueue 中取任务并执行
    • 指定一下线程池中最大线程数 maxWorkerCount ,当当前线程数超过这个最大值就不再新增线程
    1. import java.util.LinkedList;
    2. import java.util.List;
    3. import java.util.concurrent.LinkedBlockingQueue;
    4. import java.util.concurrent.ThreadPoolExecutor;
    5. public class Demo10 {
    6. //MyWork 负责完成组织一个线程的工作
    7. public static class MyWork extends Thread {
    8. private LinkedBlockingQueue queue;
    9. public MyWork(LinkedBlockingQueue queue) {
    10. super();
    11. this.queue = queue;
    12. }
    13. @Override
    14. public void run() {
    15. try {
    16. while (!Thread.interrupted()){
    17. Runnable runnable = queue.take();
    18. runnable.run();
    19. }
    20. } catch (InterruptedException e) {
    21. throw new RuntimeException(e);
    22. }
    23. }
    24. }
    25. //Study.MyThreadPool 负责完成组织所有的线程
    26. public static class MyThreadPool {
    27. private int maxContain = 10;//最多开辟多少个线程
    28. private LinkedBlockingQueue queue = new LinkedBlockingQueue<>();
    29. private List workList = new LinkedList<>();
    30. public void submit(Runnable runnable) throws InterruptedException {
    31. if (maxContain > queue.size()) {//如果线程数量没有达到最大则优先创建一个新线程执行任务
    32. MyWork work = new MyWork(queue);
    33. workList.add(work);
    34. work.start();
    35. }
    36. queue.put(runnable);
    37. }
    38. }
    39. public static void main(String[] args) throws InterruptedException {
    40. MyThreadPool pool = new MyThreadPool();
    41. pool.submit(new Runnable() {
    42. @Override
    43. public void run() {
    44. System.out.println("111");
    45. }
    46. });
    47. }
    48. }

     

  • 相关阅读:
    课程表 循环依赖 拓扑排序 go语言
    springboot 项目非docker 部署自动启动
    四.镜头知识之放大倍率
    RK3399应用开发 | 编译安装 mesa 3D 图形库(23.0.0)
    react源码分析:babel如何解析jsx
    python用cv2画图(line, rectangle, text等)
    软件工程17-18期末试卷
    抖音矩阵系统源码独立部署,抖音SEO源码定制。
    前端自动脚本中常见的几个问题,你遇到了吗?
    数据结构-带头双向循环链表(增删查改)(2)
  • 原文地址:https://blog.csdn.net/qq_52328493/article/details/127415687