线程池 Myth丶恋晨 2023-06-13 08:49 2阅读 0赞 ## 阻塞队列 ## 结构: Collection 接口 | Queue 接口 | BlockingQueue接口 | 实现类 ArrayBlockingQueue 底层数组,创建时需指定大小,无界。 LinkedBlockingQueue 底层链表,默认长度21亿。 SynchronousQueue 不存储元素,而是直接将生产出的元素丢给消费者。 阻塞队列常用API: <table> <thead> <tr> <th></th> <th align="center"><strong>抛出异常</strong></th> <th align="center"><strong>特殊值</strong></th> <th align="center"><strong>阻塞</strong></th> <th align="center"><strong>超时</strong></th> </tr> </thead> <tbody> <tr> <td>插入</td> <td align="center">add(e)</td> <td align="center">offer(e)</td> <td align="center">put(e)</td> <td align="center">offer(e, time,unit)</td> </tr> <tr> <td>移除</td> <td align="center">remove()</td> <td align="center">poll()</td> <td align="center">take()</td> <td align="center">poll(time,unit)</td> </tr> <tr> <td>检查</td> <td align="center">element()</td> <td align="center">peek()</td> <td align="center">/</td> <td align="center">/</td> </tr> </tbody> </table> ## 线程池 ## #### 核心类: #### Executor 接口 | ExecutorService接口 | 实现类ThreadPoolExecutor #### 常见线程池: #### * newFixedThreadPool: Executors.newFixedThreadPool(5) 创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,然后执行完线程池再把这个线程回收,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。 * newSingleThreadExecutor: Executors.newSingleThreadExecutor() 这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来**串行执行**。 * newCachedThreadPool: Executors.newCachedThreadPool 创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制。 * newScheduledThreadPool(int corePoolSize)(了解) 创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。 示范代码: public class ThreadPoolDemo { public static void main(String[] args) throws InterruptedException { // 指定线程数 ExecutorService threadPool = Executors.newFixedThreadPool(5); // 只有一个 ExecutorService threadPool2 = Executors.newSingleThreadExecutor(); // 自己能忙过来就自己干,忙不过来就请帮手 ExecutorService threadPool3 = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { threadPool3.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在执行任务"); } }); Thread.sleep(500); } } } #### 线程池 重要参数: #### 这三个线程池, 1. 底层都是用的ThreadPoolExecutor 2. 并且都是7个参数 3. 并且调动方法都一样 4. 使用的LinkedBlockingQueue 底层链表,默认长度21亿 ##### 线程池的7个参数包括: ##### 1. `int corePoolSize` 2. `int maxiumPoolSize` 3. `long keepAliveTime` 4. `TimeUnit unit` 5. `BlockingQueue workQueue` 6. `ThreadFactory threadFactory` 7. `RejectedExecutionHandler handler` * corePoolSize:线程池核心池大小,也就是常驻的核心线程数 * maxiumPoolSize:最大池大小,也就是最大线程数 * keepAliveTime:多于的空闲线程的存活时间,当前线程池数量超过corePoolSize时,当高峰期过去,空闲时间达到keepAliveTime还没线程需要处理任务.,多余空闲线程会被销毁,相当于从maxiumPoolSize缩容回corePoolSize,减少资源消耗 * unit:keepAliveTime的单位 * workQueue:放任务的,候客区,用于排队等候队列。 * threadFactory:默认工厂 * RejectedExecutionHandler:拒绝策略 ##### RejectedExecutionHandler 的四种拒绝策略: ##### 1. AbortPolicy(默认):直接抛出RejectedExecutionException异常,组织系统正常运行。 2. CallerRunsPolicy:调用者运行一种调用机制,该策略不会抛出异常,而是将某些任务退回给调用者,从而降低流量。 3. DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入到队列中再尝试提交任务。 4. DiscardPolicy:直接丢弃任务,不予处理,如果允许任务丢失,这是最好的解决方案。 ##### 线程池都有哪些状态? ##### 线程池有5种状态:Running、ShutDown、Stop、Tidying、Terminated。 线程池各个状态切换框架图: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg3NjY0NA_size_16_color_FFFFFF_t_70] ##### 线程池中 submit()和 execute()方法有什么区别? ##### * 接收的参数不一样 * submit有返回值,而execute没有 * submit方便Exception处理 ##### 工作的线程的数量是怎么算的?经验 ##### 1. CPU型 这些多线程程序在进行大量的运算 线程数=CPU核数+1 2. IO型 没有大量的计算 CPU的2倍或3倍 示例代码: public class ThreadPoolDemo { public static void main(String[] args) throws InterruptedException { // 指定线程数 ExecutorService threadPool = Executors.newFixedThreadPool(5); // 只有一个 ExecutorService threadPool2 = Executors.newSingleThreadExecutor(); // 自己能忙过来就自己干,忙不过来就请帮手 ExecutorService threadPool3 = Executors.newCachedThreadPool(); // 工作中自定义线程池 ExecutorService threadPoolExecutor = new ThreadPoolExecutor(2,4,1L, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy()); for (int i = 0; i < 7; i++) { threadPoolExecutor.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在执行任务"); } }); } } } #### 手写线程池(了解) #### 线程池是Executors,底层是LinkedBlockingQueue,而LinkedBlockingQueue的底层是一个链表,大小是21亿 public class FixedThreadPool { // 阻塞队列 private BlockingQueue<Runnable> taskQueue; // 集合 private List<Worker> works; public FixedThreadPool(int poolSize,int taskNum){ taskQueue = new LinkedBlockingDeque<>(taskNum); works = new ArrayList<>(); for (int i = 0; i < poolSize; i++) { Worker w = new Worker(this); w.start(); works.add(w); } } public boolean execute(Runnable r){ return taskQueue.offer(r); } private static class Worker extends Thread{ FixedThreadPool pool = null; public Worker(FixedThreadPool pool){ this.pool = pool; } public void run(){ while(true){ Runnable task = null; try { task = pool.taskQueue.take(); if(task!=null){ task.run(); } } catch (InterruptedException e) { e.printStackTrace(); } } } } } public class ThreadPoolDemo { public static void main(String[] args) { // 自己手写线程池 FixedThreadPool threadPool4 = new FixedThreadPool(5,8); for (int i = 0; i < 10; i++) { threadPool4.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在执行任务"); } }); } } } 线程池执行任务,调用execute方法,任务提交到阻塞队列中,`taskQueue.offer(r)`提交之前new了poolSize,准备好线程数,w.start();准备好了5个线程,这些线程进入run方法的while循环中,从阻塞队列里拿task,拿出来的就是提交的task。 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg3NjY0NA_size_16_color_FFFFFF_t_70]: https://img-blog.csdnimg.cn/20191114224649378.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg3NjY0NA==,size_16,color_FFFFFF,t_70
相关 Java 线程池、Runnable线程池、Callable线程池 线程池: 其实就是一个容纳多个线程的容器,其中的线程可以反复的使用,省去了频繁创建和销毁过程对象的操作,无需反复创建线程面消耗过多资源。 为什么要用线程池: 合理 青旅半醒/ 2023年02月26日 12:30/ 0 赞/ 77 阅读
相关 线程、线程池 创建线程的3种方法: package com.frank.threadPool.createThread; / @author 小石潭记 布满荆棘的人生/ 2022年10月22日 04:27/ 0 赞/ 410 阅读
相关 线程池 1.所谓线程池,就是程序的初始化阶段,就预先创建一批线程,每个线程都做好准备干活; 2.然后有一个任务列表,一开始为空,当有任务来了,就往任务列表里面添加;这个任务列表 痛定思痛。/ 2022年06月13日 13:22/ 0 赞/ 346 阅读
相关 线程池 西施越溪女,明艳光云海 最近用线程池和不用线程池做了个速度的测试,在这里备注下: 结果是速度不相上下; public static void main(Str 妖狐艹你老母/ 2022年05月20日 02:35/ 0 赞/ 300 阅读
相关 线程池 线程池 Java里面线程池的顶级接口是 java.util.concurrent.Executor , 但是严格意义上讲 Executor并不是一个线程池,而只是一个 迈不过友情╰/ 2022年03月06日 14:34/ 0 赞/ 420 阅读
相关 线程池 线程池 > 从字面义上来讲,是指管理一组同构工作线程的资源池。线程池是与工作队列密切相关的,其中在工作队列中(Worker Queue)保存了所有等待执行的任务。工作者( 清疚/ 2021年12月11日 03:35/ 0 赞/ 404 阅读
相关 线程池 可preStart一个或全部core thread 0,小于core则来一个任务建一个线程(firstTask),队列,额外线程,拒绝 一个AtomicInteger的 今天药忘吃喽~/ 2021年11月23日 03:40/ 0 赞/ 434 阅读
相关 线程池 1、先创建线程池 import java.util.concurrent.ArrayBlockingQueue; import java.util.concu 拼搏现实的明天。/ 2021年11月09日 14:28/ 0 赞/ 442 阅读
还没有评论,来说两句吧...