设为首页 加入收藏

TOP

12分钟从Executor自顶向下彻底搞懂线程池(五)
2023-09-09 10:25:36 】 浏览:111
Tags:12分 钟从 Executor 向下彻 程池
nbsp; } catch (Throwable x) {                       thrown = x; throw new Error(x);                   } finally {                       //执行后钩子方法                       afterExecute(task, thrown);                   }               } finally {                   task = null;                   w.completedTasks++;                   w.unlock();               }           }           completedAbruptly = false;       } finally {           processWorkerExit(w, completedAbruptly);       }   }

在执行前后预留两个钩子空方法,留给子类来扩展,后文处理线程池异常也会用到

配置参数

线程池中是不是越多线程就越好呢?

首先,我们要明白创建线程是有开销的,程序计数器、虚拟机栈、本地方法栈都是线程私有的空间

并且线程在申请空间时,是通过CAS申请年轻代的Eden区中一块内存(因为可能存在多线程同时申请所以要CAS)

线程太多可能导致Eden空间被使用太多导致young gc,并且线程上下文切换也需要开销

因此,线程池中线程不是越多越好,行业内分为两种大概方案

针对CPU密集型,线程池设置最大线程数量为CPU核心数量+1,避免上下文切换,提高吞吐量,多留一个线程兜底

针对IO密集型,线程池设置最大线程数量为2倍CPU核心数量,由于IO需要等待,为了避免CPU空闲就多一些线程

具体业务场景需要具体分析,然后加上大量测试才能得到最合理的配置

Executor框架通过静态工厂方法提供几种线程池,比如:Executors.newSingleThreadExecutor()Executors.newFixedThreadPool()Executors.newCachedThreadPool()

但由于业务场景的不同,最好还是自定义线程池;当理解线程池参数和实现原理后,查看它们的源码并不难,我们不过多叙述

处理异常

线程池中如果出现异常会怎么样?

Runnable

当我们使用Runnable任务时,出现异常会直接抛出

         threadPool.execute(() -> {
             int i = 1;
             int j = 0;
             System.out.println(i / j);
         });

面对这种情况,我们可以在Runnable任务中使用try-catch进行捕获

         threadPool.execute(() -> {
             try {
                 int i = 1;
                 int j = 0;
                 System.out.println(i / j);
             } catch (Exception e) {
                 System.out.println(e);
             }
         });

实际操作的话用日志记录哈,不要打印到控制台

Callable

当我们使用Callable任务时,使用submit方法会获取Future

         Future<Integer> future = threadPool.submit(() -> {
             int i = 1;
             int j = 0;
             return i / j;
         });

如果不使用Future.get()去获取返回值,那么异常就不会抛出,这是比较危险的

为什么会出现这样的情况呢?

前文说过执行submit时会将Callable封装成FutureTask执行

在其实现Runnable中,在执行Callable任务时,如果出现异常会封装在FutureTask中

     public void run() {
         //...其他略
         try {
             //执行call任务
             result = c.call();
             ran = t
首页 上一页 2 3 4 5 6 7 8 下一页 尾页 5/9/9
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇适配器模式:如何让不兼容的接口.. 下一篇原型模式和深拷贝,浅拷贝

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目