多线程并发调用feign,outcome返回NullPointerException

本文主要是介绍多线程并发调用feign,outcome返回NullPointerException,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

遇到的问题

看过我之前的文章能发现我从小就有一个并发梦,并且也是对线程协程纤程异步以及并发包有一些了解。这次的接口正好需要多次查询,并发调用feign请求提上日程。

List<Future<CurveLineDataVO>> futureList = Lists.newArrayList();
for (CurveDTO curveDTO : curveDTOList) {RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);Callable<CurveLineDataVO> callable = () -> getIntervalFlowCurve(curveDTO);futureList.add(pool.submit(callable));
}
for (Future<CurveLineDataVO> future : futureList) {try {curveLineDataVOS.add(future.get());} catch (InterruptedException e) {log.error("future.get()失败", e);} catch (ExecutionException e) {throw new RuntimeException(e.getCause().getMessage());}
}

可是,future.get一直抛出NullPointerException。
调试发现返回的FutTask对象的

state = 3;
outcome = NullPointerException

查找资料得知原因是HttpServletRequest 为null

Spring Boot 默认使用ThreadLocal把Request设置进请求线程中,这样如果在请求方法里面另起一个子线程然后再通过getRequestAttributes方法获取,是获取不到的。
。。。。。。。。。。。。。。。。。。
在Spring cloud微服务中,feign开启了熔断器(hystrix):feign.hystrix.enabled=ture,并且使用默认的信号隔离级别,、HttpServletRequest对象在父线程与子线程是相互独立的,不共享的。所以子线程中使用父线程的HttpServletRequest数据为null。

如上,加一句问题确实得到了解决。

RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);

但是并没有完全解决:用线程池时,新创建的线程能传入token,线程已经存在被再次利用时还是拿不到。这时需要结合threadLocal,Feign的拦截器,来解决问题。

三次请求:for循环与线程池加callable的效率差距有一倍。
并发调用feign

线程池ThreadPoolExecutor参数设置

解决了调用不通的问题后,就该解决如何设置线程池来提高资源利用性价比。
corePoolSize、maxPoolSize、queueCapacity。
核心线程数、最大线程数、队列容量对线程池是否继续创建线程的影响关系如下:

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满
    1. 若线程数小于最大线程数,创建线程
    2. 若线程数等于最大线程数,抛出异常,拒绝任务
这方面还需要继续学习。以下是这次实践的一些体会。

阿里java开发规范说不要用Executors创建线程池。

Executors.newFixedThreadPool()

由于这个接口调用才会用到线程池,所以将corePoolSize设置为大于0,没任务也会存活,难免觉得浪费资源。
但是当corePoolSize=0时,其他参数怎么设置,效率都上不来,例如:

private static final ExecutorService  pool = new ThreadPoolExecutor(
0, 20, 5L, TimeUnit.SECONDS, 
new LinkedBlockingQueue<>());
原因是

他会将任务加入队列,然后创建一个线程执行,队列不满不会创建更多的线程去执行。导致线程池只有一个线程活跃。
线程池
如图,只有thread1.
于是,我想着,若是队列满了会怎样呢,把队列的容量设置为1

private static final ExecutorService  pool = new ThreadPoolExecutor(
0, 20, 5L, TimeUnit.SECONDS, 
new LinkedBlockingQueue<>(1));

执行线程确实多了,效率提升明显。
执行线程
但是这样的设置也有一个致命的缺陷。
就是当maxPoolSize太小了,任务数量太多,就会被拒绝而报错。

java.util.concurrent.RejectedExecutionException
Task java.util.concurrent.FutureTask@53b8ecad rejected from java.util.concurrent.ThreadPoolExecutor@1ad994af

allowCoreThreadTimeout

还有一个allowCoreThreadTimeout参数,或许能达到我想让线程池不断给我创建新的线程去执行,同时在空闲时也不占用资源。
allowCoreThreadTimeout = true
能让核心线程在超时后退出,直到核心线程数量=0

最后决定

private static final ThreadPoolExecutor pool;static {pool = new ThreadPoolExecutor(3, 5, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());pool.allowCoreThreadTimeOut(true);
}

这篇关于多线程并发调用feign,outcome返回NullPointerException的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/677944

相关文章

统一返回JsonResult踩坑的记录

《统一返回JsonResult踩坑的记录》:本文主要介绍统一返回JsonResult踩坑的记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录统一返回jsonResult踩坑定义了一个统一返回类在使用时,JsonResult没有get/set方法时响应总结统一返回

MyBatis设计SQL返回布尔值(Boolean)的常见方法

《MyBatis设计SQL返回布尔值(Boolean)的常见方法》这篇文章主要为大家详细介绍了MyBatis设计SQL返回布尔值(Boolean)的几种常见方法,文中的示例代码讲解详细,感兴趣的小伙伴... 目录方案一:使用COUNT查询存在性(推荐)方案二:条件表达式直接返回布尔方案三:存在性检查(EXI

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET

Java空指针异常NullPointerException的原因与解决方案

《Java空指针异常NullPointerException的原因与解决方案》在Java开发中,NullPointerException(空指针异常)是最常见的运行时异常之一,通常发生在程序尝试访问或... 目录一、空指针异常产生的原因1. 变量未初始化2. 对象引用被显式置为null3. 方法返回null

C/C++和OpenCV实现调用摄像头

《C/C++和OpenCV实现调用摄像头》本文主要介绍了C/C++和OpenCV实现调用摄像头,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录准备工作1. 打开摄像头2. 读取视频帧3. 显示视频帧4. 释放资源5. 获取和设置摄像头属性

Python函数返回多个值的多种方法小结

《Python函数返回多个值的多种方法小结》在Python中,函数通常用于封装一段代码,使其可以重复调用,有时,我们希望一个函数能够返回多个值,Python提供了几种不同的方法来实现这一点,需要的朋友... 目录一、使用元组(Tuple):二、使用列表(list)三、使用字典(Dictionary)四、 使

python多线程并发测试过程

《python多线程并发测试过程》:本文主要介绍python多线程并发测试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、并发与并行?二、同步与异步的概念?三、线程与进程的区别?需求1:多线程执行不同任务需求2:多线程执行相同任务总结一、并发与并行?1、

使用Python实现调用API获取图片存储到本地的方法

《使用Python实现调用API获取图片存储到本地的方法》开发一个自动化工具,用于从JSON数据源中提取图像ID,通过调用指定API获取未经压缩的原始图像文件,并确保下载结果与Postman等工具直接... 目录使用python实现调用API获取图片存储到本地1、项目概述2、核心功能3、环境准备4、代码实现

使用@Cacheable注解Redis时Redis宕机或其他原因连不上继续调用原方法的解决方案

《使用@Cacheable注解Redis时Redis宕机或其他原因连不上继续调用原方法的解决方案》在SpringBoot应用中,我们经常使用​​@Cacheable​​注解来缓存数据,以提高应用的性能... 目录@Cacheable注解Redis时,Redis宕机或其他原因连不上,继续调用原方法的解决方案1

Python多进程、多线程、协程典型示例解析(最新推荐)

《Python多进程、多线程、协程典型示例解析(最新推荐)》:本文主要介绍Python多进程、多线程、协程典型示例解析(最新推荐),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 目录一、multiprocessing(多进程)1. 模块简介2. 案例详解:并行计算平方和3. 实现逻