Java线程池基础介绍

一、线程池的优点

  1、线程池能够复用已经创建了的线程来执行任务,从而降低了频繁创建和销毁线程所带来的资源消耗;

  2、任务创建完成时,不必等待线程的创建,能够立即执行,提高了任务响应的速度。

 

二、创建线程池的七大核心参数

  1、corePoorSize 核心线程数

     线程池中长期存活的线程数量。一般情况下,当线程处于空闲状态时也不会被销毁。

  2、maximumPoorSize 最大线程数

     线程池中允许创建的最大线程数量。当线程池队列满后,能够创建的最大线程数量(核心线程总数量 + 非核心线程总数量)。

  3、keepAliveTime 存活时间

     非核心线程的最大空闲时间。当非核心线程处于空闲状态的时长到达这个时间,就会被销毁。

  4、TimeUnit 时间单位

     存活时间的时间单位。

  5、workQueue 线程池工作队列

     存放工作任务的阻塞队列。当有任务被提交时,若没有线程能够处理,该任务就会被放到队尾,等待线程执行。

  6、threadFactory 线程工厂

     创建一个新的线程时,用到的线程工程。可以用来设置线程名等线程参数。

  7、handler 拒绝策略

     当线程池中的工作线程数量达到了最大线程数量,并且工作队列也容量也满了,此时有任务提交进来时,需要做的处理。

 

三、线程池的执行流程

 如图,线程池的执行策略可以分为三个步骤:

  1、当任务提交时,若此时的工作线程数小于核心线程数,则会创建一个线程来执行任务;

  2、当核心线程数已满时,如果此时阻塞队列没有满,则将任务放入到阻塞队列中,等待线程执行;

  3、若核心线程数和阻塞队列都已满时,会去判断当前线程数是否达到最大线程数,没有达到就会创建一个非核心线程来执行任务,达到就执行拒绝策略。

 

四、常用的四种工作队列

  1、ArrayBlockingQueue 基于数组的有界阻塞队列

    当核心线程数已满,会将新的任务放到队列当中,并按照FIFO的顺序等待线程调度。若队列中的任务达到给定的数值,则会启动新的线程去执行任务,若当前线程数量到达最大线程数量,则拒绝执行任务。

  2、LinkedBlockingQuene 基于链表的无界阻塞队列

    也是按照FIFO的,容量为Integer类型的最大值,所以近似于无界。所以maxPoolSize此时就是无效的,因为队列无界,能够不断添加任务,导致不会去创建非核心线程,线程数量最多等于核心线程数量,达不到最大线程数量。

  3、SynchronousQuene 不缓存任务的阻塞队列

    相当于没有队列,当当前线程数达到corePoolSize时,直接创建非核心线程执行任务,当当前线程数到达maxPoolSize后,则拒绝任务。

  4、PriorityBlockingQueue 具有优先级的无界阻塞队列

    默认情况下,元素采用自然顺序升序排列,也可以自定义类,然后实现compareTo()方法来指定元素排序规则。

 

五、常用的四种拒绝策略

  1、AbortPolicy

    中止策略,直接抛出 RejectedExecutionException 错误。线程池默认使用的策略。

    编写一个简单的执行deno:

public static void main(String[] args) {
        // 创建一个线程池
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2, 5, 3L, TimeUnit.MINUTES, new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.AbortPolicy() );

        for (int i = 0; i < 100; i++) {
            int finalI = i;
            poolExecutor.execute(() -> {
                try {
                    Thread.sleep(1000);
                    System.out.println("[" + Thread.currentThread().getName() + "]:" + finalI + "同学完成");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        poolExecutor.shutdown();
    }

     执行结果:达到最大线程数后,直接抛出错误

 

  2、CallerRunsPolicy 

    调用者执行策略,将任务返回给提交该任务的线程执行。

    执行demo不变,将执行策略换为CallerRunsPolicy,运行结果:

     可见,因为我们的main线程提交任务给线程池后,线程池队列及线程数量都已满,便将执行的任务返回给main线程,由main线程执行。

  3、DiscardPolicy

    丢弃策略,将该任务丢弃,且不抛出异常。

    执行demo不变,将执行策略换为DiscardPolicy,运行结果:

     达到最大线程数后,不执行提交的任务。

  4、DiscardOldestPolicy

    丢弃最老的策略,丢弃队列最前面的任务。

    执行demo不变,将执行策略换为DiscardOldestPolicy,运行结果:

     0~5号任务执行过程中,不断有新的任务提交,最后执行到了第99号任务,因为前面的不断被丢弃,99最后被放入队列并被线程执行。

热门相关:洪荒二郎传   回眸医笑,冷王的神秘嫡妃   道君   半仙   民国之文豪崛起