如何自定义线程池

  1. corePoolSize 核心线程数
  2. maximumPoolSize 最大线程数
  3. keepAliveTime 线程存活时间【超出核心线程数的那部分】
  4. unit 时间单位
  5. workQueue 任务队列
  6. threadFactory, 线程工厂,自定义线程的名字【用户自定义线程构造】
  7. 拒绝策略 handler
  • AbortPolicy中止策略 使用该策略时在饱和时会抛出RejectedExecutionException(继承自RuntimeException),调用者可捕获该异常自行处理。

  • DiscardPolicy抛弃策略 不做任何处理直接抛弃任务

  • DiscardOldestPolicy抛弃旧任务策略 先将阻塞队列中的头元素出队抛弃,再尝试提交任务。如果此时阻塞队列使用PriorityBlockingQueue优先级队列,将会导致优先级最高的任务被抛弃,因此不建议将该种策略配合优先级队列使用。

  • CallerRunsPolicy调用者运行 既不抛弃任务也不抛出异常,直接运行任务的run方法,换言之将任务回退给调用者来直接运行。使用该策略时线程池饱和后将由调用线程池的主线程自己来执行任务,因此在执行任务的这段时间里主线程无法再提交新任务,从而使线程池中工作线程有时间将正在处理的任务处理完成。

  • 线程睡眠 Thread.sleep (long millis)方法当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。

  • 线程等待 Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 唤醒方法。

  • 线程礼让 Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程.

  • 线程自闭 join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

  • suspend() 和 resume() 两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume() 被调用,才能使得线程重新进入可执行状态。典型地,suspend() 和 resume() 被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用 resume() 使其恢复。Thread中suspend()和resume()两个方法在JDK1.5中已经废除,不再介绍。因为有死锁倾向。

1
2
3
4
5
6
7
 public ThreadPoolExecutor(int corePoolSize,// 线程池的核心线程数量
                              int maximumPoolSize,// 线程池的最大线程数
                              long keepAliveTime,// 当线程数大于核心线程数时,多余的空闲线程存活的最长时间
                              TimeUnit unit,// 时间单位
                              BlockingQueue<Runnable> workQueue,// 任务队列,用来储存等待执行任务的队列
                              ThreadFactory threadFactory,// 线程工厂,用来创建线程,一般默认即可
                              RejectedExecutionHandler handler) // 拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务

image-20210820140104734

线程池原理

img

口述原理:

  1. 创建一个任务,进入这个线程池, 如果 这个 核心线程空闲,直接执行任务
  2. 如果核心线程不空闲,先进入这个 任务队列
  3. 任务队列满了, 看看 线程数少于最大线程数
  4. 如果少于,就 创建线程 【设置 存活时间,如果执行完超过这么长的时间,就死亡】
  5. 如果超过最大线程数了,执行拒绝策略