• 线程池ThreadPoolExecutor参数分析


    概述

    比如去火车站买票, 有7个(maximumPoolSize)售票窗口, 但只有3个(corePoolSize)窗口对外开放。那么对外开放的3个窗口称为核心线程数, 而最大线程数是7个窗口。

    如果3个窗口都被占用, 那么后来的人就必须在售票厅(SynchronousQueue、LinkedBlockingQueue或者ArrayBlockingQueue)排队。

    但后来售票厅人越来越多, 已经人满为患, 就类似于线程队列已满。这时候火车站站长下令, 把剩下的4个窗口也打开, 也就是目前已经有7个窗口同时运行。

    后来又来了一批人,7个窗口也处理不过来了, 而且售票厅人已经满了, 这时候站长就下令封锁入口,不允许其他人再进来, 这就是线程拒绝策略。

    线程存活时间指的是, 允许售票员休息的最长时间, 以此限制售票员偷懒的行为。

    售票厅-SynchronousQueue 

    public static void main(String[] args) {
            // 核心线程数
            int corePoolSize = 3;
            //最大线程数
            int maximumPoolSize = 7;
            // 非核心线程的最大空闲时间
            long keepAliveTime = 10L;
            // 队列种类
            SynchronousQueue synchronousQueue = new SynchronousQueue<Runnable>();
            //LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>();
            //ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<Runnable>(5);
            ThreadPoolExecutor threadpool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, synchronousQueue);
            for (int i = 0; i < 20; i++) {
                threadpool.execute(() -> {
                    System.out.println("线程名称:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(50000L);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                });
                System.out.println("当前线程数量:" + threadpool.getPoolSize());
                System.out.println("当前队列大小:" + synchronousQueue.size());
    
            }
        }

    输出结果

    当前线程数量:1
    Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task org.tonny.threads.threadpool.ThreadPool$$Lambda$1/20132171@cc34f4d rejected from java.util.concurrent.ThreadPoolExecutor@17a7cec2[Running, pool size = 7, active threads = 7, queued tasks = 0, completed tasks = 0]
    当前队列大小:0
        at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
    线程名称:pool-1-thread-1
        at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
    当前线程数量:2
        at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
    当前队列大小:0
        at org.tonny.threads.threadpool.ThreadPool.main(ThreadPool.java:19)
    线程名称:pool-1-thread-2
    当前线程数量:3
    当前队列大小:0
    线程名称:pool-1-thread-3
    当前线程数量:4
    当前队列大小:0
    当前线程数量:5
    当前队列大小:0
    线程名称:pool-1-thread-4
    当前线程数量:6
    当前队列大小:0
    当前线程数量:7
    当前队列大小:0
    线程名称:pool-1-thread-5
    线程名称:pool-1-thread-7
    线程名称:pool-1-thread-6
    
    Process finished with exit code -1

    拥有公平(FIFO)和非公平(LIFO)策略,非公平侧罗会导致一些数据永远无法被消费的情况。使用SynchronousQueue阻塞队列一般要求maximumPoolSizes为无界,避免线程拒绝执行操作。SynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素。

    售票厅- LinkedBlockingQueue

    public static void main(String[] args) {
            // 核心线程数
            int corePoolSize = 3;
            //最大线程数
            int maximumPoolSize = 7;
            // 非核心线程的最大空闲时间
            long keepAliveTime = 10L;
            // 队列种类
            //SynchronousQueue synchronousQueue = new SynchronousQueue<Runnable>();
            LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>();
            //ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<Runnable>(5);
            ThreadPoolExecutor threadpool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, linkedBlockingQueue);
            for (int i = 0; i < 20; i++) {
                threadpool.execute(() -> {
                    System.out.println("线程名称:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(50000L);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                });
                System.out.println("当前线程数量:" + threadpool.getPoolSize());
                System.out.println("当前队列大小:" + linkedBlockingQueue.size());
    
            }
        }

     输出结果

    当前线程数量:1
    当前队列大小:0
    当前线程数量:2
    当前队列大小:0
    线程名称:pool-1-thread-1
    线程名称:pool-1-thread-2
    当前线程数量:3
    当前队列大小:0
    当前线程数量:3
    当前队列大小:1
    当前线程数量:3
    当前队列大小:2
    当前线程数量:3
    当前队列大小:3
    当前线程数量:3
    当前队列大小:4
    当前线程数量:3
    当前队列大小:5
    当前线程数量:3
    当前队列大小:6
    当前线程数量:3
    当前队列大小:7
    线程名称:pool-1-thread-3
    当前线程数量:3
    当前队列大小:8
    当前线程数量:3
    当前队列大小:9
    当前线程数量:3
    当前队列大小:10
    当前线程数量:3
    当前队列大小:11
    当前线程数量:3
    当前队列大小:12
    当前线程数量:3
    当前队列大小:13
    当前线程数量:3
    当前队列大小:14
    当前线程数量:3
    当前队列大小:15
    当前线程数量:3
    当前队列大小:16
    当前线程数量:3
    当前队列大小:17
    
    Process finished with exit code -1 

    LinkedBlockingQueue是一个无界缓存等待队列。当前执行的线程数量达到corePoolSize的数量时,剩余的任务会在阻塞队列里等待。(所以在使用此阻塞队列时maximumPoolSizes就相当于无效了),每个线程完全独立于其他线程。生产者和消费者使用独立的锁来控制数据的同步,即在高并发的情况下可以并行操作队列中的数

    售票厅- ArrayBlockingQueue

    public static void main(String[] args) {
            // 核心线程数
            int corePoolSize = 3;
            //最大线程数
            int maximumPoolSize = 7;
            // 非核心线程的最大空闲时间
            long keepAliveTime = 10L;
            // 队列种类
            //SynchronousQueue synchronousQueue = new SynchronousQueue<Runnable>();
            //LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>();
            ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<Runnable>(5);
            ThreadPoolExecutor threadpool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, arrayBlockingQueue);
            for (int i = 0; i < 20; i++) {
                threadpool.execute(() -> {
                    System.out.println("线程名称:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(50000L);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                });
                System.out.println("当前线程数量:" + threadpool.getPoolSize());
                System.out.println("当前队列大小:" + arrayBlockingQueue.size());
    
            }
        }

     输出结果

    当前线程数量:1
    当前队列大小:0
    线程名称:pool-1-thread-1
    当前线程数量:2
    当前队列大小:0
    当前线程数量:3
    当前队列大小:0
    当前线程数量:3
    当前队列大小:1
    当前线程数量:3
    当前队列大小:2
    当前线程数量:3
    当前队列大小:3
    线程名称:pool-1-thread-2
    当前线程数量:3
    当前队列大小:4
    线程名称:pool-1-thread-3
    当前线程数量:3
    当前队列大小:5
    当前线程数量:4
    当前队列大小:5
    当前线程数量:5
    当前队列大小:5
    线程名称:pool-1-thread-4
    当前线程数量:6
    当前队列大小:5
    线程名称:pool-1-thread-5
    当前线程数量:7
    当前队列大小:5
    线程名称:pool-1-thread-7
    线程名称:pool-1-thread-6
    Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task org.tonny.threads.threadpool.ThreadPool$$Lambda$1/500977346@4769b07b rejected from java.util.concurrent.ThreadPoolExecutor@cc34f4d[Running, pool size = 7, active threads = 7, queued tasks = 5, completed tasks = 0]
        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 org.tonny.threads.threadpool.ThreadPool.main(ThreadPool.java:19)
    
    Process finished with exit code -1

    ArrayBlockingQueue是一个有界缓存等待队列,可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的任务缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当ArrayBlockingQueue已满时,会开启新的线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的任务尝试加入ArrayBlockingQueue时会报错。

  • 相关阅读:
    ‘随意’不是个好词,‘用心’才是
    servlet
    tomcat服务器
    http协议
    jdbc(Java数据库连接)
    dbcp和druid(数据库连接池)
    关于GitHub
    冒泡和递归
    python内置函数
    python四
  • 原文地址:https://www.cnblogs.com/supertonny/p/10491272.html
Copyright © 2020-2023  润新知