- 浏览: 1036536 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
繁星水:
Useful!!
Object-C之(Null)与(Bool) -
pacer123:
请问注解@ApiModelProperty 在哪个jar包下面 ...
Micro Service工具集之Swagger:可测试的样式化API文档 -
sucheng2016:
这东东真的好用么/
对象转换利器之Dozer -
zzq0324:
http://git.oschina.net/zzq0324/ ...
基于Spring-WS的Restful API的集成测试 -
lrz0534:
你好,我在maven上面下载了swagger-springmv ...
Micro Service工具集之Swagger:可测试的样式化API文档
并发数
并发数和2个因素有关,
一是系统可用的处理器核数,这个值可以通过硬件查询得到,也可以通过如下代码得到:
二是并发任务的类型,任务类型一般分为IO密集型和CPU密集型
说是有这么分,但是90%以上的的任务都是既有I/O操作,又有CPU运算的,因此我们在设定并发任务的时候,更重要的是去关注线程等待时间和线程CPU时间,这2个时间可以通过JMX从线程的ThreadInfo中获取,具体如何做的方式:http://stackoverflow.com/questions/1680865/how-can-i-monitor-cpu-usage-per-thread-of-a-java-application-in-a-linux-multipro
有了上面的2个数据,可以大致估算一个并发的线程数:
这只是一个大致估算,可以作为一个起点,在实际生产环境中,我们需要结合系统真实情况(比如是IO密集型或者是CPU密集型或者是纯内存操作)和硬件环境(CPU、内存、硬盘读写速度、网络状况等)来不断调整,寻找到系统的一个最佳性能点。
并发的执行策略
要并发执行任务,首先要做的就是拆分任务,把一个大的过程或者任务拆分成很多小的工作单元,拆分后的每一个工作单元可能相关、也可能无关,但他们在一定程度上可以充分利用CPU的特性并发的执行,从而提高并发性(性能、响应时间、吞吐量等)。
在拆分任务时,尽量把任务拆分得独立,不相互影响,但是在实际的业务场景中,工作单元之间或多或少会存在着一定的依赖关系,对于有依赖关系以及资源竞争的工作单元就涉及到任务的调度和负载均衡。另外,在并发量超过资源承载能力的情况下,也涉及各个工作单元的调度。这就涉及到并发任务的执行策略问题。
一个并发的执行策略主要包含下面几个部分:
有了思路,来看一下Java世界是怎么实现的?
任务如何执行?在Java的世界,所有的并发任务都必须放到线程Thread中执行,不管你是Runnable/Callable/TimerTask中的哪个,最终执行任务的就是Thread类,因此拆分任务就是形成一个个的小的Thread执行的任务。使用Callable可以获取到任务执行的结果,另外还有Future类可以帮助阻塞当前线程直到异步任务返回结果。
任务以何种顺序执行?在Java中控制并发任务的顺序有两部分,一是线程的优先级,但是这个不能保证一定高优先级的比低优先级的先,只是获得CPU时间片的概率会更高一点,二是,任务等待队列的顺序,即通过有序的分发任务来保证线程的执行顺序。
同时有多少个任务并发执行? 这个通过线程池大小来控制,开发者可以通过上一小节中的并发数估算值来设置线程池大小。而JDK1.5的并发包中提供了辅助类Executors,该类可以非常方便的设置线程池大小,同时解决了向线程池提交任务的入口问题。顺道说一句,其还提供了ScheduledExecutorService来解决重复调用任务的问题。
多少个个任务进入执行队列?这个值可以通过队列的长度来控制,JDK包中提供了各种BlockingQueue的实现,包括有容量限制的ArrayBlockingQueue, 可自定义顺序的PriorityBlockingQueue等等。
系统过载时选择放弃哪一个任务,如何通知应用程序这个动作?Java提供了RejectedExecutionHandler来解决此问题。JDK默认提供了四种方式处理。 DiscardPolicy:直接丢弃当前将要加入队列的任务本身; DiscardOldestPolicy:丢弃任务队列中最旧任务; AbortPolicy:抛出异常RejectedExecutionException; CallerRunsPolicy:调用者线程执行
任务执行的开始、结束应该做什么处理? JDK中首先提供了CompletionService/ExecutorCompletionService类来整合有返回值的Callable任务的所有结果,另外,还可以定制ThreadPoolExecutor的beforeExecute方法和afterExecute()方法。
综上所述,要设置一个合适的并发执行策略是很复杂的,所幸的是Doug Lea大爷在JDK1.5中为大家带来的并发包,提供了大量的辅助类帮助开发者简化这些配置,感恩。
并发模型
对于并发模型, 主要是2派观点,一派是基于内存共享的Thread模型,一派是基于消息传递的Actor模型(Event-Driven模型)。这两者的主要特征如下:
这两派的观点争执有好几十年了,这边Standford大学1995年讲述了《为什么Events优于Thread?》(http://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf), 主要观点如下:
那边Berkeley大学在2003年发表了论文《Why Events Are A Bad Idea (for high-concurrency servers)》:http://wenku.baidu.com/link?url=UmFNZN29i3XsMkUfzSUwflOH1Y_qPNbpz4H5zloshCJOC61RfKCgm1P_2iNZtdAKvTMCWsLcHnObfT-950nTlku7GZmuEURgQJXYvTXUELG 观点如下:
接着Berkeley大学在2006年自己打脸又发表了论文《The Problem With Thread》(http://wenku.baidu.com/link?url=eCpQcSFqxxIqaRfsoeDcycIVJI0Ff5hqFtU3OWquldRg5ahQx-jQmh2aKj4-H91EP8dhCCErOiKMGTqsuYznVhNDevimi7e2WorofDBRVcm), 表述的观点如下:
对于这两种模型,个人觉得见仁见智了,条条大路通罗马,关键是你通过对自己的问题分析觉得它适合于哪一种模型。
并发数和2个因素有关,
一是系统可用的处理器核数,这个值可以通过硬件查询得到,也可以通过如下代码得到:
Runtime.getRuntime().availableProcessors();
二是并发任务的类型,任务类型一般分为IO密集型和CPU密集型
- I/O 密集的任务通常行为是反复去读写磁盘文件,执行任务时,观察 CPU 占用的话多数时间都是出于 I/O wait 状态。这种情况下,当一个任务阻塞在IO操作上时,我们可以立即切换执行其他任务或启动其他IO操作请求,这样并发就可以帮助我们有效地提升程序执行效率。
- CPU 密集则是大量 CPU 时间都用于进行计算。这种情况下,可以将问题拆分为子任务、并发执行各子任务并最终将子任务的结果汇总合并以提升效率。
说是有这么分,但是90%以上的的任务都是既有I/O操作,又有CPU运算的,因此我们在设定并发任务的时候,更重要的是去关注线程等待时间和线程CPU时间,这2个时间可以通过JMX从线程的ThreadInfo中获取,具体如何做的方式:http://stackoverflow.com/questions/1680865/how-can-i-monitor-cpu-usage-per-thread-of-a-java-application-in-a-linux-multipro
有了上面的2个数据,可以大致估算一个并发的线程数:
引用
最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU核数
这只是一个大致估算,可以作为一个起点,在实际生产环境中,我们需要结合系统真实情况(比如是IO密集型或者是CPU密集型或者是纯内存操作)和硬件环境(CPU、内存、硬盘读写速度、网络状况等)来不断调整,寻找到系统的一个最佳性能点。
并发的执行策略
要并发执行任务,首先要做的就是拆分任务,把一个大的过程或者任务拆分成很多小的工作单元,拆分后的每一个工作单元可能相关、也可能无关,但他们在一定程度上可以充分利用CPU的特性并发的执行,从而提高并发性(性能、响应时间、吞吐量等)。
在拆分任务时,尽量把任务拆分得独立,不相互影响,但是在实际的业务场景中,工作单元之间或多或少会存在着一定的依赖关系,对于有依赖关系以及资源竞争的工作单元就涉及到任务的调度和负载均衡。另外,在并发量超过资源承载能力的情况下,也涉及各个工作单元的调度。这就涉及到并发任务的执行策略问题。
一个并发的执行策略主要包含下面几个部分:
- 任务在如何执行
- 任务以什么顺序执行(FIFO/LIFO/优先级等)
- 同时有多少个任务并发执行
- 允许有多少个个任务进入执行队列
- 系统过载时选择放弃哪一个任务,如何通知应用程序这个动作
- 任务执行的开始、结束应该做什么处理
有了思路,来看一下Java世界是怎么实现的?
任务如何执行?在Java的世界,所有的并发任务都必须放到线程Thread中执行,不管你是Runnable/Callable/TimerTask中的哪个,最终执行任务的就是Thread类,因此拆分任务就是形成一个个的小的Thread执行的任务。使用Callable可以获取到任务执行的结果,另外还有Future类可以帮助阻塞当前线程直到异步任务返回结果。
任务以何种顺序执行?在Java中控制并发任务的顺序有两部分,一是线程的优先级,但是这个不能保证一定高优先级的比低优先级的先,只是获得CPU时间片的概率会更高一点,二是,任务等待队列的顺序,即通过有序的分发任务来保证线程的执行顺序。
同时有多少个任务并发执行? 这个通过线程池大小来控制,开发者可以通过上一小节中的并发数估算值来设置线程池大小。而JDK1.5的并发包中提供了辅助类Executors,该类可以非常方便的设置线程池大小,同时解决了向线程池提交任务的入口问题。顺道说一句,其还提供了ScheduledExecutorService来解决重复调用任务的问题。
多少个个任务进入执行队列?这个值可以通过队列的长度来控制,JDK包中提供了各种BlockingQueue的实现,包括有容量限制的ArrayBlockingQueue, 可自定义顺序的PriorityBlockingQueue等等。
系统过载时选择放弃哪一个任务,如何通知应用程序这个动作?Java提供了RejectedExecutionHandler来解决此问题。JDK默认提供了四种方式处理。 DiscardPolicy:直接丢弃当前将要加入队列的任务本身; DiscardOldestPolicy:丢弃任务队列中最旧任务; AbortPolicy:抛出异常RejectedExecutionException; CallerRunsPolicy:调用者线程执行
任务执行的开始、结束应该做什么处理? JDK中首先提供了CompletionService/ExecutorCompletionService类来整合有返回值的Callable任务的所有结果,另外,还可以定制ThreadPoolExecutor的beforeExecute方法和afterExecute()方法。
综上所述,要设置一个合适的并发执行策略是很复杂的,所幸的是Doug Lea大爷在JDK1.5中为大家带来的并发包,提供了大量的辅助类帮助开发者简化这些配置,感恩。
并发模型
对于并发模型, 主要是2派观点,一派是基于内存共享的Thread模型,一派是基于消息传递的Actor模型(Event-Driven模型)。这两者的主要特征如下:
Events | Threads |
event handlers | monitors |
events accepted by a handler | functions exported by a module |
SendMessage/AwaitReply | procedure call,or fork/join |
SendReply | return from procedure |
waiting for messages | waiting on condition variables |
这两派的观点争执有好几十年了,这边Standford大学1995年讲述了《为什么Events优于Thread?》(http://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf), 主要观点如下:
引用
现在我们有点滥用Thread,Thread是基于共享内存做同步的,同时线程池的执行顺序都是预先设定好的,这就会导致死锁,出了问题很难调试,编程模型被破坏,无法使用回调等问题,而Event-Driven的编程模型,因为没有共享状态,就不需要担心死锁,同步的问题, 而且因为每个Event Handler都有自己处理域的所有信息,因此bug的调试变得简单,另外,无锁也使得在单个CPU上Event模型的性能高于Thread模型。另外,作者也承认Thread模型也有优于Event模型的地方,比方说在多个CPU上的并行能力,另外,Event模型中当某个Event Handler耗时过长时可能导致系统假死等。最终作者的结论是我们应该首先考虑使用Event模型,在一些性能要求特别苛刻的场景下,才考虑使用高端的Thread技巧,去把多核的性能发挥到极致。
那边Berkeley大学在2003年发表了论文《Why Events Are A Bad Idea (for high-concurrency servers)》:http://wenku.baidu.com/link?url=UmFNZN29i3XsMkUfzSUwflOH1Y_qPNbpz4H5zloshCJOC61RfKCgm1P_2iNZtdAKvTMCWsLcHnObfT-950nTlku7GZmuEURgQJXYvTXUELG 观点如下:
引用
其实事件驱动并没有在功能上有比线程有什么优越之处,但编程要麻烦很多,而且特别容易出错。线程的问题,无非是目前的实现的原因。一个是线程占的资源太大,一创建就分配几个MB的stack,一般的机器能支持的线程大受限制。针对这点,可以用自动扩展的stack,创建的先少分点,然后动态增加。第二个是线程的切换负担太大,Linux中实际上process和thread是一回事,区别就在于是否共享地址空间。解决这个问题的办法是用轻量级的线程实现,通过合作式的办法来实现共享系统的线程。这样一个是切换的花费很少,另外一个可以维护比较小的stack。他们用coroutine和nonblocking I/O(用的是poll()+thread pool)实现了一个原型系统,证明了性能并不比事件驱动差。
接着Berkeley大学在2006年自己打脸又发表了论文《The Problem With Thread》(http://wenku.baidu.com/link?url=eCpQcSFqxxIqaRfsoeDcycIVJI0Ff5hqFtU3OWquldRg5ahQx-jQmh2aKj4-H91EP8dhCCErOiKMGTqsuYznVhNDevimi7e2WorofDBRVcm), 表述的观点如下:
引用
目前,程序的模型基本上是基于顺序执行。顺序执行是确定性的,容易保证正确性。而人的思维方式也往往是单线程的。线程的模式是强行在单线程,顺序执行的基础上加入了并发和不确定性。这样程序的正确性就很难保证。线程之间的同步是通过共享内存来实现的,你很难来对并发线程和共享内存来建立数学模型,其中有很大的不确定性,而不确定性是编程的巨大敌人。作者以他们的一个项目中的经验来说明,保证多线程的程序的正确性,几乎是不可能的事情。首先,很多很简单的模式,在多线程的情况下,要保证正确性,需要注意很多非常微妙的细节,否则就会导致deadlock或者race condition。其次,由于人的思维的限制,即使你采取各种消除不确定的办法,比如monitor,transactional memory,还有promise/future,等等机制,还是很难保证面面俱到。以作者的项目为例,他们有计算机科学的专家,有最聪明的研究生,采用了整套软件工程的流程:design review, code review, regression tests, automated code coverage metrics,认为已经消除了大多数问题,不过还是在系统运行4年以后,出现了一个deadlock。作者说,很多多线程的程序实际上存在并发错误,只不过由于硬件的并行度不够,往往不显示出来。随着硬件的并行度越来越高,很多原来运行完好的程序,很可能会发生问题。我自己的体会也是,程序NPE,core dump都不怕,最怕的就是race condition和deadlock,因为这些都是不确定的(non-deterministic),往往很难重现。
对于这两种模型,个人觉得见仁见智了,条条大路通罗马,关键是你通过对自己的问题分析觉得它适合于哪一种模型。
发表评论
-
使用Hystrix守护应用(3)
2015-01-02 22:04 12875监控HystrixCommand 除了隔离依赖服务的调用外,H ... -
使用Hystrix守护应用(2)
2014-12-30 14:35 16816接上篇(http://ningandjiao.iteye.co ... -
使用Hystrix守护应用(1)
2014-12-30 14:28 15283Hystrix(https://github.com/Netf ... -
Mac下同时安装多个版本的JDK
2014-04-14 21:42 33240JDK8 GA之后,小伙伴们喜大普奔,纷纷跃跃欲试,想体验一下 ... -
性能测试工具之Gatling
2014-01-15 19:27 17297Gatling一直是久闻其名但 ... -
JavaMail测试工具之GreenMail
2014-01-08 19:13 7367不管现在各种Mock框架的运用有多广,我个人在写单元测试的时候 ... -
定制一个Gradle Plugin --- project-structure
2014-01-03 21:23 8494最近在项目中遇到一个 ... -
Restful Spring MVC应用的Request验证
2013-12-26 15:05 23368在开放平台的时候,尤其是坐Rest服务的时候,因为用户可以给你 ... -
Spring MVC中的异常处理
2013-12-25 13:13 24166在一个良好的Rest架构的应用中,所有的异常都应该有对应的Ht ... -
Spring 4.0升级小贴士
2013-12-22 19:40 11439随着Spring4.0的发布,很多同志估计都在考虑升级的事情了 ... -
Spring4.0给我们带来什么?
2013-12-22 17:13 45031JDK8 对JDK8的支持,这个目前来说还是探索性质,毕竟Ja ... -
RESTful API版本控制策略
2013-12-15 19:51 31740做RESTful开放平台,一方面其API变动越少, 对API调 ... -
对象转换利器之Dozer
2013-12-14 22:46 19879在Java的世界中,经常会 ... -
基于Spring-WS的Restful API的集成测试
2013-11-28 19:41 9068在很多Java企业级应用中,Spring占据了非常重要的位置, ... -
TDD Of Spring JMS
2013-11-25 19:53 1760不知何时养成了习惯,在没有一个可运行的测试的时候,个人完全没有 ... -
Micro Service工具集之Swagger:可测试的样式化API文档
2013-09-28 19:55 44740在我之前的一篇博文中,介绍了Yammer开发团队贡献的开源微服 ... -
进击的Java开发
2013-07-14 20:48 5913今天在公司的邮件组中看到一组很有趣的讨论,这是我最喜欢目前公司 ... -
说说SpringBatch的领域概念
2013-06-21 20:32 3625谈到Spring Batch,会谈到 ... -
做项目时需要考虑的安全性问题
2013-04-16 20:20 4786在开发一个项目的时候,大家经常会忽略项目的安全性问题,有很多的 ... -
使用Gradle部署jar包到Maven中央库
2013-04-12 16:15 24164Maven作为目前Java界最好的Dependency管理系统 ...
相关推荐
在软件性能测试中,了解并发用户数、吞吐量、思考时间的计算公式是非常重要的。本篇文章将从三个方面进行探讨,分别是软件性能的关注点、软件性能的几个主要术语和性能测试指标计算公式。 一、软件性能的关注点 在...
综上所述,《Java并发编程实战》不仅涵盖了Java并发编程的基础知识和技术细节,还包含了丰富的实践经验和前瞻性的思考,是任何一位从事Java开发工作的程序员不可或缺的学习资源。无论是初学者还是有经验的开发者都能...
在软件性能测试中,有三个核心概念:并发用户数、吞吐量和思考时间。这些指标对于评估系统的性能和用户体验至关重要。 并发用户数是指在同一时刻能够有效交互的用户数量。计算平均并发用户数的公式是 C=nL / T,...
本文将从高性能高并发服务器架构的优化心得、架构设计问题、负载均衡技术、开源平台的高并发集群思考等多方面详细介绍高性能高并发服务器架构的解决方案。 一、高性能高并发服务器架构的优化心得 高性能高并发...
响应时间、并发用户数、吞吐量和思考时间是软件性能测试中的四个核心概念,它们在衡量系统性能和用户体验上起着至关重要的作用。 响应时间是指用户发起请求到系统返回结果给用户所经历的时间,包括网络传输时间、...
这本书不仅仅是理论上的灌输,更多的应当是结合实践的思考和应用,使读者能够在工作中游刃有余地解决并发编程遇到的各种问题。 当然,书中内容的学习和理解,需要读者有一定的Java基础和编程经验。对于初学者来说,...
这就要求设计者必须重新思考计算模型,理解新的设计方法,并掌握一套新的编程工具集。 此外,在设计可扩展的并发数据结构时还会遇到新的挑战,即当系统能够支持越来越多的并发线程时,如何保证数据结构仍然能够保持...
Java并发编程技术总结,所含内容有并发特性、并发锁、线程池、并发场景解决方案等,对于性能思考和内容参考资料有一定说明
书中提供的实例和案例分析有助于加深理解,同时,英文版可以为有英语基础的读者提供更多的视角和思考。 无论是初学者还是经验丰富的开发者,都应该将这本书作为必备的参考资料,因为并发编程始终是多线程应用程序...
此外, LoadRunner 还提供了多种方式来模拟并发用户数,例如,使用 LoadRunner 的 scenario->Rendezvous 点 policy 来设置并发用户数,也可以使用 LoadRunner 的 Think Time 功能来模拟用户的思考时间。 虚拟用户数...
产科椎管内麻醉神经并发症认识和思考.ppt
在数据库系统中,确保并发事务的数据完整性是至关重要的任务,这涉及到并发控制和事务处理的理论与实践。本文将深入探讨并发事务中的数据完整性保证机制,主要包括事务的ACID属性、锁定策略、多版本并发控制(MVCC)...
程序的运行结果和实践思考部分将展示学生对这些概念的理解和应用能力。 通过这样的课程设计,学生不仅能够掌握Linux内核中的并发控制原理,还能提升在实际问题中解决问题的能力。同时,心得体会部分可以帮助学生...
开源平台的高并发集群思考 - **关键技术**: - **Memcached**:分布式缓存系统,用于减轻数据库负担。 - **Redis**:提供持久化的键值存储,支持多种数据结构。 - **消息队列**:如RabbitMQ、Kafka等,用于解耦...
11.1 对性能的思考183 11.1.1 性能与可伸缩性184 11.1.2 评估各种性能权衡因素185 11.2 Amdahl定律186 11.2.1 示例:在各种框架中隐藏的串行部分188 11.2.2 Amdahl定律的应用189 11.3 线程引入的开销189 ...
在多并发环境中,确保数据表数据完整性是一项挑战,特别是在分配连续序列如档案库位置或票据号码的情况下。在并发事务中,如果不采取适当的并发控制措施,可能会导致数据重复或丢失,影响系统的正确运行。以下是对...
这种麻醉方法虽然降低了全身麻醉的风险,如气道困难、误吸以及新生儿Apgar评分降低,但它也可能引发神经并发症,对母婴安全构成威胁。 神经并发症是产科椎管内麻醉中不可忽视的问题。根据给出的资料,神经并发症的...