做广告公司网站建设价格,网站建设的具体方法,wordpress怎么修改中文字体,建筑公司招聘岗位阻塞队列的应⽤——线程池一 线程池基本概念二 线程池三种常⽤创建⽅式2.1.newFixedThreadPool线程池#xff1a;2.2.newSingleThreadExecutor线程池#xff1a;2.3.newCachedThreadPool线程池#xff1a;2.4. 线程池代码演示三 线程池创建的七个参数四 线程池底层原理理解2.2.newSingleThreadExecutor线程池2.3.newCachedThreadPool线程池2.4. 线程池代码演示三 线程池创建的七个参数四 线程池底层原理理解案例图原理图流程图线程池使用注意五 线程池的拒绝策略AbortPolicy拒绝策略CallerRunsPolicy拒绝策略DiscardOldestPolicy拒绝策略DiscardPolicy拒绝策略六 实际⽣产使⽤哪⼀个线程池七 ⾃定义线程池参数选择一 线程池基本概念
概念 线程池主要是控制运⾏线程的数量将待处理任务放到等待队列然后创建线程执⾏这些任务。 如果超过了最⼤线程数则等待。 为什么⽤线程池 10年前单核CPU电脑假的多线程像⻢戏团⼩丑玩多个球CPU需要来回切换。 现在是多核电脑多个线程各⾃跑在独⽴的CPU上不⽤切换效率⾼。 线程池的优点 线程池做的⼯作主要是控制运⾏的线程数量处理过程中将任务放⼊队列然后在线程创建后启动这些任务如果线程数量超过了最⼤数量超出数量的线程排队等候等其他线程执⾏完毕再从队列中取出任务来执⾏。 线程池的主要特点为线程复⽤控制最⼤并发数管理线程。
线程复⽤不⽤⼀直new新线程重复利⽤已经创建的线程来降低线程的创建和销毁开销节省系统资源。提⾼响应速度当任务达到时不⽤创建新的线程直接利⽤线程池的线程。管理线程可以控制最⼤并发数控制线程的创建等。
体系 Executor→→ExecutorService→AbstractExecutorService→ThreadPoolExecutor。 ThreadPoolExecutor是线程池创建的核⼼类。类似Arrays、Collections工具类Executor也有自己的工具类Executors。 二 线程池三种常⽤创建⽅式
2.1.newFixedThreadPool线程池
使⽤ LinkedBlockingQueue实现定⻓线程池。 特点执⾏⻓期任务性能好创建⼀个线程池⼀池有N个固定的线程有固定线程数的线程
2.2.newSingleThreadExecutor线程池
使⽤ LinkedBlockingQueue实现⼀池只有⼀个线程。 特点⼀个任务⼀个任务的执⾏⼀池⼀线程
2.3.newCachedThreadPool线程池
使⽤ SynchronousQueue实现变⻓线程池。 特点执⾏很多短期异步任务线程池根据需要创建新线程但在先前构建的线程可⽤时将重⽤他们。 可扩容遇强则强
2.4. 线程池代码演示
任务类 模拟十个客户来办理业务 private static void threadPoolTask(ExecutorService threadPool) {//模拟有10个顾客来办理业务try {for (int i 1; i 10; i) {threadPool.execute(() - {System.out.println(Thread.currentThread().getName() \t办理业务);try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}});}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();}}newFixedThreadPool线程池 创建线程数为5观察结果发现5个线程一起执行 //一个池子有5个工作线程类似银行有5个受理窗口threadPoolTask(Executors.newFixedThreadPool(5));newSingleThreadExecutor线程池
创建newSingleThreadExecutor线程池观察结果发现只有一个线程可以使用。
System.out.println(Single Thread Pool);// //一个池子有1个工作线程类似银行有1个受理窗口threadPoolTask( Executors.newSingleThreadExecutor() );newCachedThreadPool线程池 创建newCachedThreadPool观察结果有10个客户就有10个线程执行任务。有可能业务员办事快接着又给其他客户办理业务 System.out.println(Cached Thread Pool);// //不定量线程一个池子有N个工作线程类似银行有N个受理窗口threadPoolTask( Executors.newCachedThreadPool() );问题 上述我们使用10个客户来模拟如果用100个呢我们来观察结果
三 线程池创建的七个参数 参数意义corePoolSize线程池中的常驻核⼼线程数maximumPoolSize线程池中能够容纳同时并发的最⼤线程数此值必须⼤于等于1keepAliveTime多余的空闲线程的存活时间当前池中线程数量超过corePoolSize时当空闲时间达到keepAliveTime时多余线程会被销毁直到只剩下corePoolSize个线程为⽌unitkeepAliveTime存活时间的单位workQueue任务队列存放已提交但尚未执⾏的任务threadFactory表示⽣成线程池中⼯作线程的线程⼯⼚⽤于创建线程⼀般默认的即可handler拒绝策略表示当队列满了并且⼯作线程⼤于等于线程池的最⼤线程数maximumPoolSize时如何来拒绝请求执⾏的runnable的策略
四 线程池底层原理
理解
线程池的创建参数就像⼀个银⾏。
corePoolSize就像银⾏的“当值窗⼝“⽐如今天有2位柜员在受理客户请求任务。如果超过2个客户那么新的客户就会在等候区等待队列workQueue等待。当等候区也满了这个时候就要开启“加班窗⼝”让其它3位柜员来加班此时达到最⼤窗⼝maximumPoolSize为5个。如果开启了所有窗⼝等候区依然满员此时就应该启动”拒绝策略handler 告诉不断涌⼊的客户 叫他们不要进⼊已经爆满了。由于不再涌⼊新客户办完事的客户增多窗⼝开始空闲这个时候就通过 keepAlivetTime将多余的3个”加班窗⼝“取消恢复到2个”当值窗⼝“
案例图 原理图
上⾯银⾏的例⼦实际上就是线程池的⼯作原理。
流程图 流程 在创建了线程池后开始等待请求。当调⽤execute()⽅法添加⼀个请求任务时线程池会做出如下判断 2.1 如果正在运⾏的线程数量⼩于corePoolSize那么⻢上创建核⼼线程运⾏执⾏这个任务 2.2 如果正在运⾏的线程数量⼤于或等于corePoolSize那么将这个任务放⼊队列 2.3 如果这个时候等待队列已满且正在运⾏的线程数量⼩于maximumPoolSize 那么还是要创 建⾮核⼼线程⽴刻运⾏这个任务 2.4 如果这个时候等待队列已满且正在运⾏的线程数量⼤于或等于 maximumPoolSize那么线程池会启动饱和拒绝策略来执⾏。当⼀个线程完成任务时它会从等待队列中取出下⼀个任务来执⾏。当⼀个线程⽆事可做超过⼀定的时间 keepAliveTime后线程会判断 如果当前运⾏的线程数⼤于 corePoolSize那么这个⾮核⼼线程就被停掉。当线程池的所有任 务完成后它最终会收缩到corePoolSize的⼤⼩。 线程池使用注意
《Java 开发⼿册》是阿⾥巴巴集团技术团队 五 线程池的拒绝策略 当等待队列满时且达到最⼤线程数再有新任务到来就需要启动拒绝策略。JDK提供了四种拒绝策 略分别是
AbortPolicy默认的策略直接抛出 RejectedExecutionException异常阻⽌系统正常运⾏。CallerRunsPolicy既不会抛出异常也不会终⽌任务⽽是将任务返回给调⽤者从⽽降低新任务的流量。DiscardOldestPolicy抛弃队列中等待最久的任务然后把当前任务加⼊队列中尝试再次提交任务。DiscardPolicy该策略默默地丢弃⽆法处理的任务不予任何处理也不抛出异常。如果允许任务丢失这是最好的⼀种策略。
AbortPolicy拒绝策略 CallerRunsPolicy拒绝策略 DiscardOldestPolicy拒绝策略 DiscardPolicy拒绝策略 六 实际⽣产使⽤哪⼀个线程池
单⼀、可变、定⻓都不⽤原因就是FixedThreadPool和 SingleThreadExecutor底层都是⽤ LinkedBlockingQueue实现的这个队列最⼤⻓度为 Integer.MAX_VALUE显然会导致OOM。所以实际⽣产⼀般⾃⼰通过的7个参数⾃定义线程池 System.out.println(Custom Thread Pool);threadPoolTask( new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy()));结果分析
七 ⾃定义线程池参数选择
对于CPU密集型任务最⼤线程数是CPU线程数1。 对于IO密集型任务文件上传下载尽量多配点可以是CPU线程数*2或者CPU线程数/(1-阻塞系数)。 IO密集型即该任务需要⼤量的IO即⼤量的阻塞。 在单线程上运⾏IO密集型的任务会导致浪费⼤量的CPU运算能⼒浪费在等待。 所以在IO密集型任务中使⽤多线程可以⼤⼤的加速程序运⾏及时在单核CPU上这种加速主要就是利⽤了被浪费掉的阻塞时间。 IO密集型时⼤部分线程都阻塞故需要多配置线程数 **参考公式**CPU核数 / 1 - 阻塞系数 阻塞系数在 0.8~0.9 之间 ⽐如 8 核 CPU8/1 - 0.9 80个线程数