• Java中的线程池


    Java中的线程池

    一、线程池的好处

      1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

      2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

      3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

    二、线程池的种类

      Java通过Executors提供四种线程池

      1. newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

      2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

      3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

      4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    三、 ThreadPoolExecutor

      1. 上述四种Java中的线程池都是用ThreadPoolExecutor实现的

      2. ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)

      3. ThreadPoolExecutor继承了AbstractExecutorService抽象类,AbstractExecutorService实现了ExecutorService接口,ExecutorService继承了Executor 接口

      • corepoolsize:核心池的大小,默认情况下,在创建了线程池之后,线程池中线程数为 0,当有任务来之后,就会创建一个线程去执行任务,当线程池中线程数达到 corepoolsize 后,就把任务放在任务缓存队列中。
      • Maximumpoolsize:线程池中最多创建多少个线程。
      • Keeplivetime:线程没有任务执行时,最多保存多久的时间会终止,默认情况下,当线程池中线程数>corepoolsize ,Keeplivetime 才起作用,直到线程数不大于 corepoolsize。
      • workQueue:阻塞队列,用来存放等待被执行的任务
      • threadFactory:线程工厂,用来创建线程。

         4. ThreadPoolExecutor继承了AbstractExecutorService抽象类,AbstractExecutorService实现了ExecutorService接口,ExecutorService继承了Executor 接口

      

     

    四、 线程池生命周期/状态转换过程

      1. RUNNING :当线程池创建后,初识为Running状态,能接受新提交的任务,并且也能处理阻塞队列中的任务;

      2. SHUTDOWN:关闭状态,不再接受新提交的任务,但却可以继续处理阻塞队列中已保存的任务。在线程池处于 RUNNING 状态时,调用 shutdown()方法会使线程池进入到该状态。(finalize() 方法在执行过程中也会调用shutdown()方法进入该状态);

      3. STOP:不能接受新任务,也不处理队列中的任务,会中断正在处理任务的线程。在线程池处于 RUNNING 或 SHUTDOWN 状态时,调用 shutdownNow() 方法会使线程池进入到该状态;

      4. TIDYING:如果所有的任务都已终止了,workerCount (有效线程数) 为0,线程池进入该状态后会调用 terminated() 方法进入TERMINATED 状态。

    五、 线程池的组成

      1. 线程池管理器:用于创建并管理线程池

      2. 工作线程:线程池中的线程

      3. 任务接口:每个任务必须实现的接口,用于工作线程调度其运行

      4. 任务队列:用于存放待处理的任务,提供一种缓冲机制

    六、 execute方法执行流程

      1. addWorker方法的主要工作是在线程池中创建一个新的线程并执行,firstTask参数用于指定新增的线程执行的第一个任务,core参数为true表示在新增线程时会判断当前活动线程数是否少于corePoolSize,false表示新增线程前需要判断当前活动线程数是否少于maximumPoolSize

      2. 下述添加到工作线程并执行,调用的就是addWorker()

      3. submit方法能获得线程执行后的返回值,底层还是调用了execute方法

      4. execute方法工作流程

      • 若当前线程池中线程数<corepoolsize,则每来一个任务就创建一个线程去执行,即使现在的线程是空闲的。
      • 若当前线程池中线程数>=corepoolsize,会尝试将任务添加到任务缓存队列中去,若添加成功,则任务会等待空闲线程将其取出执行,若添加失败,则尝试创建线程去执行这个任务。
      • 若当前线程池中线程数>= Maximumpoolsize,则采取拒绝策略有 4 种,

          1)abortpolicy 丢弃任务,抛出 RejectedExecutionException

          2)discardpolicy 拒绝执行,不抛异常

          3)discardoldestpolicy 丢弃任务缓存队列中最老的任务,并且尝试重新提交新的任务

          4)callerrunspolicy 有反馈机制,使任务提交的速度变慢。

    七、 工作线程整个工作流程

      1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

      2. 当调用 execute()/submit() 方法添加一个任务时,会进行上述线程数量判断过程(线程池创建线程时,会将线程封装成工作线程Worker),并执行addWorker() 添加并执行任务

      3. 调用addWorker()中的runWorker()方法执行任务firstTask,firstTask执行完成之后,通过getTask方法从阻塞队列中获取等待的任务,如果队列中没有任务,getTask方法会被阻塞并挂起,不会占用cpu资源;

      4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

  • 相关阅读:
    STL容器list容器API
    STL容器之list基本概念
    STL容器queue的API
    做tab切换时,点击浏览器返回拿不到实时的tab参数,请求不到实时的数据
    v-for渲染出来的列表,要根据不同的状态改变样式,通过给标签添加lang属性完成
    清除每隔5000毫秒请求一次接口的定时器(需求:每当我手动核销电子码,页面上的显示数据要实时更新到)
    ES6数组解构赋值
    es6 var、let、const命令
    canvas计算高度(自定义高度)
    Vue 点击button请求接口,接收不到返回的参数
  • 原文地址:https://www.cnblogs.com/Demrystv/p/9404582.html
Copyright © 2020-2023  润新知