并发编程:线程池详解、Forkjoin详解

线程池的好处

  • 降低频繁创建、销毁线程的开销
  • 便于统一管理线程(数量等)
  • 提高响应时间

Java中的线程池

  • Executors:创建线程池的工厂类。
  • Executors.newFixedThreadPool(nThreads):创建固定大小的线程池。
  • Executors.newCachedThreadPool():无限线程池。
  • Executors.newSingleThreadExecutor():创建单个线程的线程池。
  • Executors.newScheduledThreadPool():创建跑定时任务的线程池。

这4个线程池底层都是调用的new ThreadPoolExcutor(),这个构造方法有很多参数,下面一一分析

  • coolPoolSize:核心线程数
  • maxPoolSize:最大线程数
  • waitTime:线程空闲等待时间
  • timeUnit:时间单位
  • 阻塞队列
  • 拒绝策略:有4种
    • 直接抛异常
    • 直接丢弃任务
    • 将队列中最老的任务丢掉并将新任务入队
    • 直接用当前线程执行该任务
  • 线程工厂
这些参数和线程池的执行流程有关,线程池的执行流程:
  • 当任务提交到线程池时,假如当前线程数小于核心线程数,直接创建线程执行,并且不会销毁,直到达到核心线程数。
  • 当核心线程都在执行还有任务提交时,任务放在阻塞队列中。
  • 阻塞队列也满了以后,继续创建线程执行任务,直到达到最大线程数。
  • 最大线程也满了以后,执行对应的拒绝策略。
  • 当线程空闲下来以后,线程在达到线程空闲等待时间后销毁,直至数量降低至核心线程数。

addWorker():1、增加工作线程数(cas增加一个标记位)2、创建工作线程。
Worker是一个Runnable对象,还继承了AQS,重写了获取state和释放state的方法,没有实现重入特性。1、lock表示正在执行任务,不应该被中断,也不应该被其他的线程重入;2、shutdown的时候会去加锁,只有无锁的时候才可以终止,不可重入导致shutdown不能解锁,必须等工作结束再终止。
执行任务时会加锁,为了在shutdown时不终止正在进行的任务。
最大线程结束的原因是while(getTask()!=null)有超时时间,返回null则跳出循环结束。

Future/Callable

实现原理:FutureTask:run()方法result字段保存返回值,保存好了以后会唤醒阻塞的线程,get()方法拿不到结果时会阻塞,内部使用awaitNode在链表中阻塞。

Fork/join

分治思想,拆分任务fork然后join归并,底层实现了一种叫工作窃取的算法来提高效率。

posted @ 2020-07-15 00:33  挣扎一下  阅读(2205)  评论(0编辑  收藏  举报