线程池:TreadPoolExecutor

线程池:

  • TreadPoolExecutor:

    • 使用int的高3位标识线程池状态,低29位标识线程数;

    • 这些信息存储在一个原子变量中,将线程状态和个数合二为一,方便进行原子操作

      状态名 高3位 接受新任务 处理阻塞队列任务 说明
      RUNNING 111 Y Y 刚创建的线程池
      shutdown 000 N Y 不再接受新任务,但会处理剩余任务;
      stop 001 N N 中断正在执行的任务,并抛弃阻塞队列任务;
      tidying 010 - - 任务全执行完毕,活动线程为0即将进入终结;
      terminated 011 - - 终结状态;
    • 从数字上面比较:terminated > tidying > stop > shutdown >running【负数】

    • 构造方法:

      public TreadPoolExecutor(
      	int corePoolSize, //核心线程数目,最多保留线程数;
      	int maxinumPoolSize, //最大线程数;
          int keepAliveTime, //生存时间-针对急救线程;
          TimeUnit unit, //时间单位-针对急救线程;
          BlockingQueue<Runnable> workQueue, //阻塞队列;
          ThreadFactory threadFactory, //线程工厂,起名字;
          RejectedExecutionHandler handler, // 拒绝策略;
      )
      
      • 线程,最大线程数 = 核心 + 救急
        • 核心线程:没有存活时间;
        • 救急线程:当阻塞队列满了后还有任务,会创建【临时工】;
          • int keepAliveTime, //生存时间-针对急救线程
          • TimeUnit unit, 单位;
        • 当为无界队列的时候,阻塞队列无容量限制的时候,就不存在救济线程;
        • RejectedExecutionHandler handler, /拒绝策略:当阻塞队列,核心,救济都满后,采取拒绝策略;
        • 拒绝策略,前四种,jdk实现:
          • AbortPolicy:抛出RejectedExecutionException异常,默认;
          • CallerRunsPolicy:让调用者则运行;
          • DiscardPolicy:放弃本次任务;
          • DiscardOldestPolicy:放弃最早的任务,本任务取代;
          • Dubbo的实现:抛出异常之前记录日志,并dump线程栈信息,方便定位问题;
          • Netty的实现:创建一个新线程来执行;
          • ActiveMQ的实现:带超时等待【60s】,尝试放入队列;
          • PinPoint:使用一个拒绝策略,逐一尝试策略链中中的每中策略;
      • Executor工厂方法:
        • newFixedThreadPool:
          • 核心线程数 = 最大线程数【无救急线程】;
          • 采用LinkedBlockingQueue<Runnable>,为无界阻塞队列;
          • 适用于已知的任务量;
        • newCachedThreadPool:
          • 核心线程数为0,最大线程数是Integer.MAX_VALUE,救急线程的空闲生存时间是60s【全是救急线程,60s回收】;
            • 密集任务,任务持续较短
          • 队列采取:SynchronousQueue,他没有容量,方便直接交给救急线程;
            • put()方法是一个阻塞方法,直到被take()方法取走;
        • newSingleThreadExecutor:
          • 核心线程数 = 最大线程数 = 1,而且放入newFixedThreadPool相同的无界阻塞队列,
          • 便于串行执行任务,而且始终维持着线程;
          • 和newFixedThreadPool区别:
            • 使用装饰器模式,只对外暴露了接口方法,没有暴露ThreadPoolExecutor对象的核心方法;
      • 提交任务:
        • execute(Runnable runnable):没有返回结果;
        • <T> Future<T> submit(Callable<T> task):具有返回值,future中的阻塞方法get,当值返回时,会唤醒并使用get得到;
        • <T>List<Future<T>>invokeAll(Collection<? extends Callable <T> tasks);
        • <T>List<Future<T>>invokeAll(Collection<? extends Callable <T> tasks, long timeout, TimeUnit unit);
        • <T> T invokeAny(Collection<? extends Callable <T> tasks):只执行一个任务,只有又有一个完成,并返回,其他任务自动取消【找到最快执行的任务】;
      • 关闭线程:
        • shutdown:不在接受新任务,但执行完已提交任务;
          • 不是阻塞方法,不会等待;
        • shutdownNow:线程状态改变为Stop,
          • 队列中的任务会返回【List<Runnable>】,打断正在执行的任务;
        • isShutdown();
        • isTerminated();
        • awaitTermination():有时限的等待;
  • 任务调度线程池:

    • newScheduledThread() // => newFixedThread();
      • schedule(Runnable runnable, long timeout, TimeUnit):延时执行;
      • scheduleAtFixedRate():固定速率执行;
      • scheduleWithFixedDelay():以固定延时间隔执行【闹钟】;
  • 出现异常,并没有显示问题:

    • try-catch捕获;
    • submit()有异常,返回future的get异常信息;
  • tomcat中execute的修改:

  • 当抛出RejectedExecutionException异常的时候,tomcat会捕获,并再次尝试加入阻塞队列,这个次失败后,才抛出异常

  • tomcat的配置:

    • LimitLatch:用来限流,可控制的最大连接个数;
    • Acceptor:只负责接受socket连接;
    • Poller:负责监听socket channel是否有可读事件;
    • Executor线程池:一旦有可读时间,由线程池负责;
  • Fork//Join线程池:适合拆分执行任务,结果合并【cpu密集型】;

    • eg:递归任务,尽量减小任务之间的耦合性;
    • 默认创建线程数 = cpu核心数;
posted @ 2025-03-28 22:34  烟雨断桥  阅读(22)  评论(0)    收藏  举报