阅读更多

4顶
0踩

编程语言

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

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

当前环境

  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

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

  • 【JS】跨域问题读写cookie的解决办法

    跨域Cookie共享:访问A站点时已经登录从而保存姓名、头像等基本信息,这时访问该公司的B站点时就自然而然的能显示出这些基本信息,也就是实现信息共享(在银联体系中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

  • 网站跨站点单点登录

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

  • 跨页面清除Cookie信息

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

  • 渗透测试-跨站脚本攻击xss之获取cookie

    渗透测试-跨站脚本攻击xss之获取cookie

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

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

  • 原生js获取cookie获取scrf防跨站攻击token

    var _csrf = (/_csrf=[^;]+;?/i).exec(document.cookie); if(_csrf) { _csrf = _csrf[0].replace('_csrf=', '').replace(';', ''); }

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

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

  • 多域名站点共享COOKIE

    p.s. 架构轻盈,效果实现 问题描述:在一个比较复杂的网站环境下。有多个产品向外提供服务。每个产品下都有自己的用户登录界面。现在需要设计一个统一的登录界面。 当用户在这个界面登录后就可以自由的使用各个产品和服务。同时意味着用户用一个帐号可以在不同服务里登录,另一方面就是在一个服务里面登录后可以无障碍的 漫游到其他服务里面去。 实际应用:Sohu的Passport将focus.cn,17173.c

  • Asp中如何设计跨越域的Cookie

    Cookie简介   首先,我们对Cookie做一个简单的介绍,说明如何利用ASP来维护cookie。   Cookie是存储在客户端计算机中的一个小文件,这就意味着每当一个用户访问你的站点,你就可以秘密地在它的硬盘上放置一个包含有关信息的文件。这个文件几乎可以包含任何你打算设置的信息,包括用户信息、站点状态等等。这样的话,就有一个潜在的危险:这些信息有可能被黑客读取。为了防止这个问题的发...

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

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

  • 跨域Cookie的读取

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

  • Chrome 无法携带跨站cookie的各种解决方案

    同源策略的历史及对应的解决方案 当页面内发起请求时,会默认携带该域名下的cookie。 而cookie同源策略是指:除非当前域名和请求域名是同源,才会默认携带cookie。 这就导致,localhost直接请求测试环境的接口,比如 http://api.baidu.com,此时不会携带 cookie,从而导致登录失效的问题。 这一策略从chrome 80开始存在,而chrome 91升级,chrome 94再升级。 chrome 各个版本如何禁用同源cookie策略: chrome &lt; 91,可以

Global site tag (gtag.js) - Google Analytics