java - ThreadPoolExecutor线程池原理

为什么使用线程池?

  1. 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
  2. 提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;
  3. 方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换(cpu切换线程是有时间成本的(需要保持当前执行线程的现场,并恢复要执行线程的现场))。
  4. 提供更强大的功能,延时定时线程池。

线程池使用的一个例子

  • 测试性能
package com.demo.mp;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadDemo {
     

  /** * 创建线程及书写业务代码 */
  static class TxTask implements Runnable {
     

    @Override
    public void run() {
     
      System.err.println("多线程业务代码执行......");
    }
  }

  /** 使用线程池执行多线程 */
  public static void method() {
     

    // 创建线程池
    ThreadPoolExecutor executor =
        new ThreadPoolExecutor(200, 500, 601, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100));

    // 提交线程任务 +1000个线程
    for (int i = 0; i < 1000; i++) {
     
      executor.execute(new TxTask());
    }

    // 线程池关闭
    executor.shutdown();
  }

  /**
   * * 每五秒执行一次method方法创建1000个线程
   *
   * @param args
   */
  public static void main(String[] args) {
     
    while (true) {
     
      try {
     
        Thread.sleep(5000);
      } catch (InterruptedException e) {
     
        e.printStackTrace();
      }
      // 创建1000个线程
      method();
      // 告诉垃圾收集器打算进行垃圾收集,而垃圾收集器进不进行收集是不确定的
      System.gc();
    }
  }
}

ThreadPoolExecutior神秘面纱

ThreadPoolExecutior()线程池中的主要参数

  • 新例子:
package com.demo.mp;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolDemo {
     

  /** * 创建线程及书写业务代码 */
  static class TxTask implements Runnable {
     

    @Override
    public void run() {
     
      System.err.println(Thread.currentThread().getName() + "多线程业务代码执行......");
    }
  }
  
  public static void main(String[] args) {
     
    // 创建线程池
    ThreadPoolExecutor executor =
        new ThreadPoolExecutor(5, 10, 601, TimeUnit.SECONDS, new LinkedBlockingDeque<>(5));

    // 提交线程任务 15  个线程
    for (int i = 0; i < 15; i++) {
     
      executor.execute(new TxTask());
    }

    // 线程池关闭
    executor.shutdown();
  }
}

java - ThreadPoolExecutor线程池原理_第1张图片

ThreadPoolExecutor构造器:

 public ThreadPoolExecutor(int corePoolSize,
                           int maximumPoolSize,
                           long keepAliveTime,
                           TimeUnit unit,
                           BlockingQueue<Runnable> workQueu) {
     
     this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
          Executors.defaultThreadFactory(), defaultHandler);
 }
    
 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
     
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
    
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
     
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
    
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
     
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

  1. corePoolSize :线程池中的核心线程数
  2. workQueue :如果目前的线程池中工作线程达到了corePoolSize,新的任务就会提交到队列,队列是可以有参数的,参数就是队列的容量,如上的demo
  3. maximumPoolSize,:线程池中最大的工作线程数量,当核心线程数满了并且队列也满了的时候,就会允许创建新的工作线程,新创建的工作线程是和初始的线程是没有任何区别的,如果遇到销毁也不会区分新旧;但是,当前核心线程数 + 额外创建的线程数 的总量不得大于 maximumPoolSize,如果超过最大值则会走拒绝策略(RejectedExecutionHandler),默认会选择AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • AbortPolicy默认拒绝策略异常信息:
    java - ThreadPoolExecutor线程池原理_第2张图片

    Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.demo.mp.ThreadPoolDemo$TxTask@5b6f7412 rejected from java.util.concurrent.ThreadPoolExecutor@27973e9b[Running, pool size = 10, active threads = 6, queued tasks = 0, completed tasks = 27]
    	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
    	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
    	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
    	at com.demo.mp.ThreadPoolDemo.main(ThreadPoolDemo.java:29)
    
  1. keepAliveTime :线程存活保持时间;当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于或等于核心线程数。
  • 销毁也不会区分新旧,谁空闲销毁谁
  1. unit : keepAliveTime值得单位,TimeUnit有对应的单位可以点进去看
  • TimeUnit.SECONDS 秒
  1. threadFactory: 线程工厂;用于创建新线程。threadFactory创建的线程也是采用new Thread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号)。

  2. handler: (线程饱和策略):当线程池和队列都满了,再加入线程会执行对应的策略。

  • 默认策略AbortPolicy
    (1)DiscardPolicy (丢弃任务,但是不抛出异常。)
    (2)DiscardOldestPolicy (丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程))
    (3)AbortPolicy - 默认策略 (丢弃任务并抛出RejectedExecutionException异常。)
    (4)CallerRunsPolicy 示例(由调用线程处理该任务)
    一览图:
    java - ThreadPoolExecutor线程池原理_第3张图片

execute()方法

后面的明天再写出去办点事。。。。。。

你可能感兴趣的:(java,java,多线程,并发编程,面试)