使用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 个参数:corePoolSize 表示线程池的常驻核心线程数。如果设置为 0,则表示在没有任何任务时,销毁线程池;如果大于 0,即使没有任务时也会保证线程池的线程数量等于此值。但需要注意,此值如果设置的比较小,则会频繁的创建和销毁线程(创建和销毁的原因会在本课时的下半部分讲到);如果设置的比较大,则会浪费系统资源,所以开发者需要根据自己的实际业务来调整此值;
-
第 2 个参数:maximumPoolSize 表示线程池在任务最多时,最大可以创建的线程数。官方规定此值必须大于 0,也必须大于等于 corePoolSize,此值只有在任务比较多,且不能存放在任务队列时,才会用到;
-
第 3 个参数:keepAliveTime 表示线程的存活时间,当线程池空闲时并且超过了此时间,多余的线程就会销毁,直到线程池中的线程数量销毁的等于 corePoolSize 为止,如果 maximumPoolSize 等于 corePoolSize,那么线程池在空闲的时候也不会销毁任何线程;
-
第 4 个参数:unit 表示存活时间的单位,它是配合 keepAliveTime 参数共同使用的;
-
第 5 个参数:workQueue 表示线程池执行的任务队列,当线程池的所有线程都在处理任务时,如果来了新任务就会缓存到此任务队列中排队等待执行;
-
第 6 个参数:threadFactory 表示线程的创建工厂,此参数一般用的比较少,我们通常在创建线程池时不指定此参数,它会使用默认的线程创建工厂的方法来创建线程;
-
第 7 个参数:RejectedExecutionHandler 表示指定线程池的拒绝策略,当线程池的任务已经在缓存队列 workQueue 中存储满了之后,并且不能创建新的线程来执行此任务时,就会用到此拒绝策略,它属于一种限流保护的机制。
第五个参数阻塞队列:有几种常见的策略
ArrayBlockingQueue:由数组结构组成的有界阻塞队列。
LinkedBlockingQueue:由链表结构组成的有界阻塞队列。
DelayQueue:使用优先级队列实现的无界阻塞队列。
PriorityBlockingQueue:至此优先级排序的无界阻塞队列。
SynchronousQueue:不储存元素的阻塞队列。
-
直接提交策略(Direct handoff): 当线程池的工作队列已满时,该策略会立即将任务交给线程池中的工作线程进行执行,并且不会将任务保存在队列中。这意味着任务提交立即与任务执行同步进行,不会进行任何形式的排队等待。如果没有空闲的工作线程,新任务将被拒绝。
-
无界队列策略(Unbounded queue): 无界队列策略使用一个没有容量限制的阻塞队列存储任务。在这种策略下,将一直接收新的任务,直到系统资源耗尽。这意味着即使线程池中的线程数达到上限,新提交的任务也会被放入队列中等待执行。这种策略可能导致内存占用过高,因此需要特别关注系统资源的管理。
-
有界队列策略(Bounded queue): 有界队列策略使用一个具有固定容量的阻塞队列来存储任务。当线程池的工作线程数达到上限时,新提交的任务将被放入队列中等待执行。如果队列已满,后续的任务将根据线程池的拒绝策略进行处理,例如抛出异常或者执行预定义的拒绝逻辑。
-
第七个策略,拒绝策略,可以根据业务需求选择,也可以自定义
以上内容纯属学习~