使用ThreadPoolExecutor线程池消化线程执行代码

此处记录一个使用ThreadPoolExecutor线程池的demo

线程池的作用:复用线程的技术

线程代码,此处使用Runnable创建线程

public class ExcutorRunnable implements Runnable{

    @Override
    public void run() {

        System.out.println(Thread.currentThread().getName() + ": 线程执行666");
        try {
            Thread.sleep(Integer.MAX_VALUE);  //此处是想看下后面拒绝策略
        } catch (InterruptedException e) {

        }
    }
}

测试main方法

public class ThreadExcutorPool {

    public static void main(String[] args) {

        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3,5,8,
                TimeUnit.SECONDS,new ArrayBlockingQueue<>(4),
                Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
        //ExecutorService service = new ScheduledThreadPoolExecutor()
        Runnable excutorRunnable = new ExcutorRunnable();
        poolExecutor.execute(excutorRunnable);
        poolExecutor.execute(excutorRunnable);
        poolExecutor.execute(excutorRunnable);
        //放到队列中
        poolExecutor.execute(excutorRunnable);
        poolExecutor.execute(excutorRunnable);
        poolExecutor.execute(excutorRunnable);
        poolExecutor.execute(excutorRunnable);
        //最大线程
        poolExecutor.execute(excutorRunnable);
        poolExecutor.execute(excutorRunnable);
        //执行拒绝策略
        poolExecutor.execute(excutorRunnable);

    }

}

控制台打印

pool-1-thread-2: 线程执行666
main: 线程执行666
pool-1-thread-4: 线程执行666
pool-1-thread-3: 线程执行666
pool-1-thread-5: 线程执行666
pool-1-thread-1: 线程执行666

上面的demo中,为啥创建线程的时候,睡眠时间这么久呢,就是想看下,如果这个核心线程数满了,队列也满了,会不会创建空闲线程数,如果空闲线程数也满了,执行的线程策略中,使用CallerRunsPolicy,会不会就当前线程执行线程去,从打印的控制台来看,是有执行,而且也有创建空余线程(核心线程3,控制台答应的线程4、5都是空余线程)

这里线程池的创建中有几个参数

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
}

每个参数的具体描述

线程池(ThreadPoolExecutor)有 7 个参数,这 7 个参数的含义如下:

  1. 第 1 个参数:corePoolSize 表示线程池的常驻核心线程数。如果设置为 0,则表示在没有任何任务时,销毁线程池;如果大于 0,即使没有任务时也会保证线程池的线程数量等于此值。但需要注意,此值如果设置的比较小,则会频繁的创建和销毁线程(创建和销毁的原因会在本课时的下半部分讲到);如果设置的比较大,则会浪费系统资源,所以开发者需要根据自己的实际业务来调整此值;

  2. 第 2 个参数:maximumPoolSize 表示线程池在任务最多时,最大可以创建的线程数。官方规定此值必须大于 0,也必须大于等于 corePoolSize,此值只有在任务比较多,且不能存放在任务队列时,才会用到;

  3. 第 3 个参数:keepAliveTime 表示线程的存活时间,当线程池空闲时并且超过了此时间,多余的线程就会销毁,直到线程池中的线程数量销毁的等于 corePoolSize 为止,如果 maximumPoolSize 等于 corePoolSize,那么线程池在空闲的时候也不会销毁任何线程;

  4. 第 4 个参数:unit 表示存活时间的单位,它是配合 keepAliveTime 参数共同使用的;

  5. 第 5 个参数:workQueue 表示线程池执行的任务队列,当线程池的所有线程都在处理任务时,如果来了新任务就会缓存到此任务队列中排队等待执行;

  6. 第 6 个参数:threadFactory 表示线程的创建工厂,此参数一般用的比较少,我们通常在创建线程池时不指定此参数,它会使用默认的线程创建工厂的方法来创建线程;

  7. 第 7 个参数:RejectedExecutionHandler 表示指定线程池的拒绝策略,当线程池的任务已经在缓存队列 workQueue 中存储满了之后,并且不能创建新的线程来执行此任务时,就会用到此拒绝策略,它属于一种限流保护的机制。

 

第五个参数阻塞队列:有几种常见的策略

ArrayBlockingQueue:由数组结构组成的有界阻塞队列。

LinkedBlockingQueue:由链表结构组成的有界阻塞队列。

DelayQueue:使用优先级队列实现的无界阻塞队列。

PriorityBlockingQueue:至此优先级排序的无界阻塞队列。

SynchronousQueue:不储存元素的阻塞队列。

  1. 直接提交策略(Direct handoff): 当线程池的工作队列已满时,该策略会立即将任务交给线程池中的工作线程进行执行,并且不会将任务保存在队列中。这意味着任务提交立即与任务执行同步进行,不会进行任何形式的排队等待。如果没有空闲的工作线程,新任务将被拒绝。

  2. 无界队列策略(Unbounded queue): 无界队列策略使用一个没有容量限制的阻塞队列存储任务。在这种策略下,将一直接收新的任务,直到系统资源耗尽。这意味着即使线程池中的线程数达到上限,新提交的任务也会被放入队列中等待执行。这种策略可能导致内存占用过高,因此需要特别关注系统资源的管理。

  3. 有界队列策略(Bounded queue): 有界队列策略使用一个具有固定容量的阻塞队列来存储任务。当线程池的工作线程数达到上限时,新提交的任务将被放入队列中等待执行。如果队列已满,后续的任务将根据线程池的拒绝策略进行处理,例如抛出异常或者执行预定义的拒绝逻辑。

  4. 优先级队列策略(Priority queue): 优先级队列策略使用一个基于优先级的阻塞队列来存储任务。每个任务都有一个相关联的优先级,高优先级的任务将被优先执行。该策略可以根据任务的优先级来决定任务的执行顺序,而不是按照任务的提交顺序。这对于一些具有紧急性或重要性要求的任务调度场景非常有用。

 

第七个策略,拒绝策略,可以根据业务需求选择,也可以自定义

 

以上内容纯属学习~

 

posted @ 2024-10-31 16:28  多多指教~  阅读(7)  评论(0编辑  收藏  举报