Java学习笔记5线程池

编程

Java学习笔记5-线程池

线程池原理 - 我的理解就是个送快递的网点

  1. 线程池管理器:用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务;- 快递网点管理者,可以招聘和辞退快递小哥,收件分件等
  2. 工作线程:线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;- 送快递的小哥
  3. 任务接口:每个任务必须实现的接口,以供工作线程调度任务的执行,他主要规定了任务的入口,任务执行完成后的收尾工作,任务的执行状态等;- 快递包裹的规格,快递单及配送信息等,没地址的快递小哥可没法送
  4. 任务队列:用于存放没有处理的任务。提供一种缓冲机制。- 存放快递包裹的仓库

线程池API

  1. Executor(接口):最上层的接口,定义了执行任务的方法execute

  2. ExecutorService(接口):继承Executor接口,扩展了Callable、Future、关闭方法

  3. ScheduledExecutorService(接口):继承ExecutorService接口,增加了定时任务相关方法

  4. ThreadPoolExecutor(实现类):基础、标准的线程池实现,推荐使用,创建线程达到核心线程数 -> 再将任务队列放满 -> 可创建线程达到最大线程数 -> 执行拒绝策略

    public ThreadPoolExecutor(int corePoolSize, // 核心线程数量

    int maximumPoolSize, // 最大线程数量

    long keepAliveTime, // 超出核心线程数量的线程空闲存活时间

    TimeUnit unit, // 存活时间单位

    BlockingQueue<Runnable> workQueue, // 等待任务队列

    ThreadFactory threadFactory, // 线程创建工厂,可选

    RejectedExecutionHandler handler // 指定拒绝策略的,可选

    ) {

    // ...

    }

    ThreadPoolExecutor测试代码

    import java.util.concurrent.LinkedBlockingQueue;

    import java.util.concurrent.RejectedExecutionHandler;

    import java.util.concurrent.ThreadPoolExecutor;

    import java.util.concurrent.TimeUnit;

    /**

    * @Author: Wenx

    * @Description:

    * @Date: Created in 2019/11/11 17:14

    * @Modified By:

    */

    public class DemoTest {

    public static void main(String[] args) throws InterruptedException {

    // 创建一个 核心线程数量为2,最大线程数量为5,等待队列为3 的线程池,相当于最大容纳8个任务

    // 默认的策略是抛出RejectedExecutionException异常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(

    2, 5, 5, TimeUnit.SECONDS,

    new LinkedBlockingQueue<Runnable>(3),

    new RejectedExecutionHandler() {

    @Override

    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

    System.err.println("快递网点:快递小哥不够仓库已满 / 停止业务 -> 拒收快递包裹");

    }

    });

    // 测试: 提交 10个 执行时间需要3秒的任务,看超过2个任务时的对应处理情况

    int num = 10;

    for (int i = 0; i < num; i++) {

    int n = i + 1;

    System.out.println("快递包裹" + n + ":到达快递网点");

    threadPoolExecutor.submit(new Runnable() {

    @Override

    public void run() {

    try {

    System.out.println("------------------------------快递小哥正在送 快递包裹" + n);

    Thread.sleep(3000L);

    System.out.println("------------------------------快递包裹" + n + " 已送达");

    } catch (InterruptedException e) {

    System.err.println("------------------------------快递小哥翻车了:" + e.getMessage());

    }

    }

    });

    System.out.println("派件快递小哥人数为:" + threadPoolExecutor.getPoolSize());

    System.out.println("网点仓库包裹数量为:" + threadPoolExecutor.getQueue().size());

    }

    // 8秒后快递包裹应该都配送完了(具体延迟时间可以调整至都配送完,还有5人=2核心+3临时)

    Thread.sleep(8000L);

    System.out.println("快递网点:快递包裹应该差不多配送完了");

    System.out.println("派件快递小哥人数为:" + threadPoolExecutor.getPoolSize());

    System.out.println("网点仓库包裹数量为:" + threadPoolExecutor.getQueue().size());

    // 没活干5秒的临时快递小哥要被辞退了(空闲5秒就要被辞退,就剩核心2人)

    Thread.sleep(5000L);

    System.out.println("快递网点:没活干5秒的临时快递小哥要被辞退");

    System.out.println("派件快递小哥人数为:" + threadPoolExecutor.getPoolSize());

    System.out.println("网点仓库包裹数量为:" + threadPoolExecutor.getQueue().size());

    threadPoolExecutor.shutdown(); // 快递网点停止业务,但现有快递包裹还会配送

    //threadPoolExecutor.shutdownNow(); // 快递网点停止业务,现有快递包裹也不会配送

    System.out.println("快递网点:停止业务");

    Thread.sleep(1000L);

    System.out.println("派件快递小哥人数为:" + threadPoolExecutor.getPoolSize());

    System.out.println("网点仓库包裹数量为:" + threadPoolExecutor.getQueue().size());

    // 再次提交提示失败

    System.out.println("快递包裹" + (num + 1) + ":到达快递网点");

    threadPoolExecutor.submit(new Runnable() {

    @Override

    public void run() {

    System.out.println("又来一个快递包裹");

    }

    });

    // 结果分析

    // 1、 2个任务(快递包裹)直接分配线程(快递小哥)开始执行(配送)

    // 2、 3个任务(快递包裹)进入等待队列(快递网点仓库)

    // 3、 队列(仓库)不够用,临时加开3个线程(快递小哥)来执行任务(5秒没活干就辞退)

    // 4、 队列(仓库)和线程池(快递小哥)都满了,剩下2个任务(快递包裹),没资源了,被拒绝执行(拒收)。

    // 5、 等待现有任务执行结束(配送完),应当还有5个任务(5人=2核心+3临时)

    // 6、 5秒后,如果无任务可执行(没活干),销毁临时创建的3个线程(辞退临时快递小哥)

    // 7、 调用shutdown(停止业务),不接收新的任务(快递包裹)

    // 8、 在线程池关闭(停止业务)后追加的任务(快递包裹),无法再提交,会被拒绝执行(拒收)

    }

    }

  5. ScheduledThreadPoolExecutor(实现类):定时任务线程池实现,继承了ThreadPoolExecutor,实现了ScheduledExecutorService中定时任务相关的方法

    public ScheduledThreadPoolExecutor(int corePoolSize) {

    super(corePoolSize, // 核心线程数量

    Integer.MAX_VALUE, // 最大线程数量

    0, // 超出核心线程数量的线程空闲存活时间

    NANOSECONDS, // 存活时间单位

    new DelayedWorkQueue() // 等待任务队列-延时队列,没有到达时间取不出来

    );

    }

    ScheduledThreadPoolExecutor测试代码

    import java.text.SimpleDateFormat;

    import java.util.concurrent.ScheduledThreadPoolExecutor;

    import java.util.concurrent.TimeUnit;

    /**

    * @Author: Wenx

    * @Description:

    * @Date: Created in 2019/11/11 17:14

    * @Modified By:

    */

    public class DemoTest {

    public static void main(String[] args) throws InterruptedException {

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

    ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);

    // 定时3秒后执行一次任务

    threadPoolExecutor.schedule(new Runnable() {

    @Override

    public void run() {

    System.out.println("定时任务1 开始执行,当前时间为:" + dateFormat.format(System.currentTimeMillis()));

    }

    }, 3000, TimeUnit.MILLISECONDS);

    System.out.println("定时任务1 提交成功,当前时间为:" + dateFormat.format(System.currentTimeMillis()));

    System.out.println("当前线程池中线程数量:" + threadPoolExecutor.getPoolSize());

    // 周期性执行任务

    // scheduleAtFixedRate:2秒后执行第一次任务,之后每间隔1秒执行一次(如果上次执行还未结束,则等待结束后立刻执行)

    threadPoolExecutor.scheduleAtFixedRate(new Runnable() {

    @Override

    public void run() {

    try {

    Thread.sleep(3000L);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println("定时任务2 开始执行,当前时间为:" + dateFormat.format(System.currentTimeMillis()));

    }

    }, 2000, 1000, TimeUnit.MILLISECONDS);

    System.out.println("定时任务2 提交成功,当前时间为:" + dateFormat.format(System.currentTimeMillis()));

    System.out.println("当前线程池中线程数量:" + threadPoolExecutor.getPoolSize());

    // scheduleWithFixedDelay:2秒后执行第一次任务,之后每间隔1秒执行一次(如果上次执行还未结束,则等待结束后,再等待1秒执行)

    threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {

    @Override

    public void run() {

    try {

    Thread.sleep(3000L);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println("定时任务3 开始执行,当前时间为:" + dateFormat.format(System.currentTimeMillis()));

    }

    }, 2000, 1000, TimeUnit.MILLISECONDS);

    System.out.println("定时任务3 提交成功,当前时间为:" + dateFormat.format(System.currentTimeMillis()));

    System.out.println("当前线程池中线程数量:" + threadPoolExecutor.getPoolSize());

    }

    }

  6. Executors(工具类):创建线程池工厂类,不推荐使用,因为创建的都是无界队列线程池,线程处理不完的话,队列有多少收多少,推荐直接使用ThreadPoolExecutor配置有界队列

    newFixedThreadPool(int nThreads):创建一个固定大小的线程池

    public static ExecutorService newFixedThreadPool(int nThreads) {

    return new ThreadPoolExecutor(nThreads, nThreads,

    0L, TimeUnit.MILLISECONDS,

    new LinkedBlockingQueue<Runnable>());

    }

    newCachedThreadPool():创建一个缓冲线程池,可以动态调整线程池大小

    public static ExecutorService newCachedThreadPool() {

    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

    60L, TimeUnit.SECONDS,

    new SynchronousQueue<Runnable>());

    }

    newSingleThreadExecutor():创建一个单一线程池

    public static ExecutorService newSingleThreadExecutor() {

    return new Executors.FinalizableDelegatedExecutorService

    (new ThreadPoolExecutor(1, 1,

    0L, TimeUnit.MILLISECONDS,

    new LinkedBlockingQueue<Runnable>()));

    }

    newScheduledThreadPool(int corePoolSize):创建一个定时执行任务的线程池

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {

    return new ScheduledThreadPoolExecutor(corePoolSize);

    }

以上是 Java学习笔记5线程池 的全部内容, 来源链接: utcz.com/z/511200.html

回到顶部