阅读更多

4顶
0踩

编程语言

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

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

当前环境

  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 跨域

    应某网友请求,做的一个Cookie跨域的简单演示 请将HTML和PHP文件放入不同的域名下测试,然后修改下面Js的调用地址

  • 跨站点设置 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的值的。 ...

  • 网络安全学习笔记——盗取Cookies跨站脚本(XSS)

    使用替换过了的URL发给目标,诱导目标点击,然后目标的cookies就会回弹到XSS攻击平台上,展开就可以看到该目标的PHPSESSID,然后在自己的同源网站上,笔记本按Fn+F12,调出Hackerbar,点击存储,然后把PHPSESSID换成攻击之后得到的,删掉浏览框里面多余的东西,剩下XXX.php即可,刷新之后就会登录该目标的账号——,SESSID——中间键,是Apache分配的,唯一的“身份证”,从SESSID入手,就可以查取用户的相关信息。

  • 跨域和cookie

    为什么会出现跨域?出于浏览器的同源策略限制,浏览器会拒绝跨域请求。什么情况下出现跨域?不同源就会跨域。同源即:协议、域名、端口号都相同。任意一项不同就会跨域。例如 https://127.0.0.1:8000为什么会有跨域需求?项目工程服务化后,不同职责的服务分散在不同的工程中,往往这些工程的域名是不同的,但一个需求可能需要对应到多个服务,这时便需要调用不同服务的接口,因此会出现跨域。跨域只是浏览器的限制,服务器没有跨域问题。

  • 跨站设置cookie

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

  • cookie跨站脚本漏洞解决方案

    近日项目碰到一个跨脚本注入的问题: 这安全测评工具也是厉害了,直接将脚本注入到cookie里头,以前没有碰到这样的情况。 之前写过一篇文章过滤跨脚本注入的问题。《浅谈XSS攻击原理与解决方法》关于跨脚本注入的问题,不晓得原理的同学可以看下。但是里头没有处理cookie注入的问题。接下来介绍下如何处理。 关键代码在这里:首先获取到cookie,检查下是否有敏感字符,如果有的话,就...

  • 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跨站点伪造攻击(CSRF)

    背景知识: 很久很久以前,Web基本上就是文档的浏览而已,既然是浏览,作为服务器,不需要纪录谁在某一段时间里浏览了什么 文档,每次请求都是一个新的Http协议,就是请求加响应,尤其是我不用记住是谁刚刚发了HTTP请求,每个请求对我 来说是全新的,这段时间很嗨皮。 但是,随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,马上就面临一个问题,那就是要管理回话, 必须记住那些人登录系统,那些人往自己的购物车中放商品,也就是说我必须把每个人区分开,这就是一个不小的挑战, 因为HTTP请求是无状态.

  • cookie 跨域问题

    cookie 跨域访问 一、 前言 随着项目模块越来越多 ,很多模块现在都是独立部署, 模块之间的交流有事可能会通过cookie完成 , 比如说门户和应用部署在不同的机器或者web容器中 , 假如用户登录之后会在浏览器客户端写入cookie (记录着用户上下文信息) , 应用想要回去门户下的cookie , 这就产生了cookie跨域的问题 。 二、 cookie介绍 c...

  • Cookie Session跨站无法共享问题(单点登录解决方案)

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

  • java cookie 跨域读取_跨域读写Cookie

    Cookie作用域Cookie 在二级域名下是可以共享的,如www.a.com 和m.a.com 他们的Cookie 是可以共享的,这也是很多单点登录利用Cookie实现的原理,但是很多站点不是二级域名的如www.taobao.com和www.tmall.com,它们是完成两个不同的域名,那么完全不同的域名可以共享Cookie吗?答案是可以的,我们看一下实现思路。跨域写Cookie跨域写Cooki...

  • xss漏洞-DVWA跨站攻击盗取用户cookie值

    程Kaedy.cn-www.kaedy.cn XSS跨站脚本攻击介绍 跨站脚本攻击英文全称为(Cross site Script)缩写为 CSS,但是为了和层叠样式表(Cascading Style Sheet)CSS 区分开来,所以在安全领域跨站脚本攻击叫做 XSS XSS 攻击简介 XSS 攻击通常指黑客通过往 Web 页面中插入恶意 Script 代码,当用户访问网页时恶意代码在用户的 浏览器中被执行,从而劫持用户浏览器窃取用户信息。 1、黑客加在特定 web 页面 index.html 中,加入

  • 面试官问:跨域请求如何携带cookie?

    大家好,我是若‍川。持续组织了6个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架...

  • 跨域Cookie的读取

    cookie的几个属性 1 httpOnly:true 表示禁止客户端读cookie,即只能在服务端读取它 2 SameSite:用来限制第三方 Cookie,从而减少安全风险。 Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。 Set-Cookie: CookieName=CookieValue; SameSite=Strict; Lax规则稍稍放宽,大多数情况也是不发送第三方 Co

Global site tag (gtag.js) - Google Analytics