阅读更多

4顶
0踩

编程语言

转载新闻 JAVA 线程池的正确打开方式

2018-02-16 10:16 by 副主编 jihong10102006 评论(1) 有8440人浏览

当前环境

  1. jdk == 1.8

Executors 使用的隐患

先来看一段代码,我们要创建一个固定线程池,假设固定线程数是4。代码如下:

Executors是JAVA并发包中提供的,用来快速创建不同类型的线程池。

是不是很简单,创建线程池只需一行代码。对于一些个人项目或临时性的项目,这样写确实没什么问题,而且开发速度很快。但在一些大型项目中,这种做法一般是禁止的。

WHY???

因为用Executors创建的线程池存在性能隐患,我们看一下源码就知道,用Executors创建线程池时,使用的队列是new LinkedBlockingQueue<Runnable>(),这是一个无边界队列,如果不断的往里加任务时,最终会导致内存问题,也就是说在项目中由于使用了无边界队列,导致的内存占用的不可控性。下图是不断添加线程任务导致老年代被占满的情况:

当然,除了内存问题,它还存在一些其他的问题,在下面对线程池参数的介绍中会具体说明。

线程池的正确创建方式

其实,问题很好解决。提供的简便方式有局限性,那我们自己new一个ThreadPoolExecutor,无非多写几行代码而已。

关于ThreadPoolExecutor的具体代码如下:

参数说明:

  • corePoolSize:核心线程数;
  • maximumPoolSize:最大线程数,即线程池中允许存在的最大线程数;
  • keepAliveTime:线程存活时间,对于超过核心线程数的线程,当线程处理空闲状态下,且维持时间达到keepAliveTime时,线程将被销毁;
  • unit:keepAliveTime的时间单位
  • workQueue:工作队列,用于存在待执行的线程任务;
  • threadFactory:创建线程的工厂,用于标记区分不同线程池所创建出来的线程;
  • handler:当到达线程数上限或工作队列已满时的拒绝处理逻辑;

具体代码

  • 自定义threadFactory。除了可以自定义创建的线程名称,方便问题排查,在newThread(Runnable r)创建线程的方法中,还可以进行定制化设置,如为线程设置特定上下文等。

  • 自定义RejectedExecutionHandler。记录异常信息,选择不同处理逻辑,有交由当前线程执行任务,有直接抛出异常,再或者等待后继续添加任务等。

  • 创建自定义线程池

线程池内在处理逻辑

我们通过一些例子,来观察一下其内部的处理逻辑。基于上述具体代码,我们已经创建了一个核心线程数4,最大线程数8,线程存活时间10s,工作队列最大容量为10的一个线程池。

  • 初始化线程池:未添加线程任务

    • 这时,线程池中***不会创建任何线程***,存活线程为0,工作队列为0.
  • 未达核心线程数:添加4个线程任务

    • 由于当前存活线程数 <= 核心线程数,所以会***创建新的线程***。即存活线程为4,工作队列为0.
  • 核心线程数已满:添加第5个线程任务

    • 若当前线程池中存在空闲线程,则交由该线程处理。即存活线程为4,工作队列为0.
    • 若当前所有线程处理运行状态,加入工作队列。即存活线程为4,工作队列为1.(注意:此时工作队列中的任务不会被执行,直到有线程空闲后,才能被处理
  • 工作队列未满:假设添加的任务都是耗时操作(短时间不会结束),再添加9个耗时任务

    • 即存活线程为4,工作队列为10.
  • 工作队列已满 & 未达最大线程数:再添加4个任务

    • 当工作队列已满,且不存在空闲线程,此时会***创建额外线程***来处理当前任务。此时存活线程为8,工作队列为10.
  • 工作队列已满 & 且最大线程数已满:再添加1个任务

    • 触发RejectedExecutionHandler,将当前任务交由自己设置的执行句柄进行处理。此时存活线程为8,工作队列为10.
  • 当任务执行完后,没有新增的任务,临时扩充的线程(大于核心线程数的)将在10s(keepAliveTime)后被销毁。

总结

最后,我们在使用线程池的时候,需要根据使用场景来自行选择。通过corePoolSize和maximumPoolSize的搭配,存活时间的选择,以及改变队列的实现方式,如:选择延迟队列,来实现定时任务的功能。并发包Executors中提供的一些方法确实好用,但我们仍需有保留地去使用,这样在项目中就不会挖太多的坑。

扩展

对于一些耗时的IO任务,盲目选择线程池往往不是最佳方案。通过异步+单线程轮询,上层再配合上一个固定的线程池,效果可能更好。类似与Reactor模型中selector轮询处理。

来自: github
4
0
评论 共 1 条 请登录后发表评论
1 楼 fanlei77 2018-02-22 14:07
请问查看内存占用情况使用的是什么工具?

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 跨站点设置 Cookie

    网站跨站点实现单点登录的实现前言实现方法跨子域(Across-Subdomains)完全跨域(Across-Domains)用户首次单点登录用户跨站访问用户退出登录结语参考资料 前言 网站的用户身份验证往往使用 Cookie 技术。用户在一个网站进行登录以及身份验证的过程一般为: 在登录页面进行登录后,将登录用户的用户名等信息加密后写在本地浏览器中,也就是一个 Cookie,我们把这个 Cookie 叫做票(Ticket)。 需要判断用户是否登录的页面,需要读取相应 Ticket,并从中解密出用户信息,

  • 两个网址登录同一浏览器,出现cookie冲突的原因及js取不到cookie的原因

    关于cookie冲突问题,js取不到cookie问题 cookie不区分端口号,如果统一IP下,不同端口号的系统,cookie会共享。所以如果你有两个系统只是端口号不同,而token信息存在了cookie,在同一浏览器登录,会出现token冲突。 后端set cookie的时候使用了httpOnly,或设置了特殊path,前端js是取不到cookie的值的。 ...

  • 跨站设置cookie

    2019独角兽企业重金招聘Python工程师标准&gt;&gt;&gt; ...

  • Cookie跨域以及Cookie共享问题

    解决跨域以后,如何允许跨域请求携带cookie,例如访问B的接口,默认情况下是不允许带cookie的,此时需要设置axios的withcredentials的属性为true,告诉浏览器在访问B网站时,将B网站的cookie带上,此时光前端设置还不行,还需要后端在响应头中添加 allow-withcredentials = true,这样就可以保证跨域请求也可以携带cookie。在站点A下面访问B域名的接口,那么这是一个跨域请求,如果不做处理,此时这个请求就跨域了,浏览器在接收到响应以后会直接报错。

  • cookie跨站点访问

    cookie跨站点访问,必须的经过服务器支持 以QQ空间和QQ朋友网为例: QQ空间域名:qq.com QQ朋友网域名:pengyou.com 1.首先登录QQ空间,网址:http://ptlogin2.qq.com/login 登录成功后,浏览器中会设置一些Cookie,如: Set-Cookie: skey=@pkkE39h1d; PATH=/; DOMAIN=qq.com

  • 跨页面清除Cookie信息

    跨页面清除Cookie信息跨页面清除Cookie信息解决方法 跨页面清除Cookie信息 最近做到了个简单的小功能,记录在cookie里的信息需要清除,Cookie信息在A页面记录,然后去B页面可以读的到A页面设置cookie信息,但是在设置cookie过期的时候提示成功,但是清除后只在A页面清除掉了,在B页面中的cookie信息还是照样存在,解决掉这个小问题后记录下来。 解决方法 由于cooki...

  • 网站跨站点单点登录

    昨天和几位朋友探讨到了这个话题,发现虽然单点登录,或者叫做独立的passport登录虽然已经有了很多实现方法,但是能真正了解并实现的人却并不太多,所以些下此文,希望从原理到实现,能让大家了解的多一些至于什么是单点登录,举个例子,如果你登录了msn messenger,访问hotmail邮件就不用在此登录。一般单点登录都需要有一个独立的登录站点,一般具有独立的域名,专门的进行注册,登录,注销等操

  • 跨域访问页面携带cookie

    跨域访问携带cookie

  • 不同网站可以共享cookie吗

    不同域名是无法共享浏览器端本地信息,包括cookies,这即是跨域问题。Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。定义于RFC2109和2965都已废弃,最新取代的规范是RFC6265。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cooki...

  • 两个不同主域之间跨域设置cookie值

    应用说明: (1)两个网站主域名不同才需要这样跨域设置(如:***.a.com,***.b.com ,a 和 b 不同的情况) (2)chrome浏览器内核才需要这样跨域设置(chrome edge 360 需要,firefox不需要,ie目前未试通) (3)浏览器登录a系统拿到cookie值,然后在a系统网页中带着cookie值参数调用b系统接口设置b主域cookie值。 1、提供cookie值一方,在网页中以ajax方式调用被设置cookie值方的接口,发送......

  • 解决跨域设置Cookie问题

    如a.123.com跨域访问b.123.com/request、 b.123.com服务器使用nginx允许跨域,Access-Control-Allow-Origin:* 如果a、b服务不在同一个服务器 前台页面请求报错信息为: Access to XMLHttpRequest at 'http://b.123.com' from origin 'http://a.123.com'...

  • 网站跨站点单点登录实现--cookie

    至于什么是单点登录,举个例子,如果你登录了msn messenger,访问hotmail邮件就不用在此登录。一般单点登录都需要有一个独立的登录站点,一般具有独立的域名,专门的进行注册,登录,注销等操作 我们为了讨论方便,把这个登录站点叫做站点P,设其Url为http://passport.yizhu2000.com,需要提供服务的站点设为A和B,跨站点单点登录是指你在A网站进行登录后,...

  • 跨站脚本攻击XSS 获取cookie (low)

    XSS 跨站脚本攻击(Cross-site scripting),简称XSS(为区分CSS),它是一种迫使 Web 站点回显可执行代码的攻击技术。 XSS分为存储型XSS(Stored XSS)和反射型XSS(Reflected XSS) 存储型XSS 思路: 黑客在服务器的某一个留言板上留言了一条可以执行的语句(这是一条命令),这条语句上有黑客的IP地址,普通用户去访问这个网站,一旦打开了留言板...

  • SSO单点登录、跨域重定向、跨域设置Cookie、京东单点登录实例分析

    最近在研究SSO单点登录技术,其中有一种就是通过js的跨域设置cookie来达到单点登录目的的,下面就已京东商城为例来解释下跨域设置cookie的过程 涉及的关键知识点: 1、jquery ajax跨域重定向,要理ajax解跨域重定向,先要了解浏览器对重定向的处理。正常我们请求一个地址,如果server返回302,那么浏览器会再发起一次重定向后的http请求;用jquery ajax发起一次异

  • 跨站、跨域、cookie注入

    简述 之前对cookie相关知识一直零零碎碎,最近工作中遇到些点相关问题,于是又整体重新梳理了一面,算是一个总结。 本章主要介绍如何跨域、跨站注入cookie,以及踩过过的一些。 文章所用到的URL说明 http://dev.proxy.com:3000/ 浏览器访问URL http://dev.fws.proxy.com:3001/跨域接口URL http://dev.other.com:3001/跨站接口URL 概念 跨站(cross-site):两个 URL 的 eTLD+...

Global site tag (gtag.js) - Google Analytics