[Java Performance] 线程及同步的性能之线程池/ThreadPoolExecutors/ForkJoinPool
- 任务被投放到一个队列中(队列的数量不定)
- 线程从队列中取得任务并执行
- 线程完成任务后,继续尝试从队列中取得任务,如果队列为空,那么线程进入等待状态
线程池往往拥有最小和最大线程数:
- 最小线程数,即当任务队列为空时,线程池中最少需要保持的线程数量,这样做是考虑到创建线程是一个相对耗费资源的操作,应当尽可能地避免,当有新任务被投入队列时,总会有线程能够立即对它进行处理。
- 最大线程数,当需要处理的任务过多时,线程池能够拥有的最大线程数。这样是为了保证不会有过多的线程被创建出来,因为线程的运行需要依赖于CPU资源和其它各种资源,当线程过多时,反而会降低性能。
在ThreadPoolExecutor和其相关的类型中,最小线程数被称为线程池核心规模(Core Pool Size),在其它Java应用服务器的实现中,这个数量也许被称为最小线程数(MinThreads),但是它们的概念是相同的。
- 任务的特征
- 计算机的硬件情况
从上面中得到一些结论:
- 当线程数为4时,达到最优性能,再增加线程数量时并没有更好的性能,因为此时CPU的利用率已经达到了最高,在增加线程只会增加线程之间争夺CPU资源的行为,因此反而降低了性能。
- 即使在CPU利用率达到最高时,基线百分比也不是理想中的25%,这是因为虽然在程序运行过程中,CPU资源并不是只被应用程序线程独享的,一些后台线程有时也会需要CPU资源,比如GC线程和系统的一些线程等。
当计算是通过Servlet触发的时候,性能数据是下面这个样子的(Load Generator会同时发送20个请求):

从上表中可以得到的结论:
- 在线程数量为4时,性能最优。因为此任务的类型是计算密集型的,只有4个CPU,因此线程数量为4时,达到最优情况。
- 随着线程数量逐渐增加,性能下降,因为线程之间会互相争夺CPU资源,造成频繁切换线程执行上下文环境,而这些切换只会浪费CPU资源。
- 性能下降的速度并不明显,这也是因为任务类型是计算密集型的缘故,如果性能瓶颈不是CPU提供的计算资源,而是外部的资源,如数据库,文件操作等,那么增加线程数量带来的性能下降也许会更加明显。
下面,从Client的角度考虑一下问题,并发Client的数量对于Server的响应时间会有什么影响呢?还是同样地环境,当并发Client数量逐渐增加时,响应时间会如下发生变化:

- 有任务需要被执行
- 当前线程池中所有的线程都处于工作状态
- 当前线程池的线程数没有达到最大线程数
至于线程池会如何创建这个新的线程,则是根据任务队列的种类:
- 线程池是对象池的一个有用的例子,它能够节省在创建它们时候的资源开销。并且线程池对系统中的线程数量也起到了很好的限制作用。
- 线程池中的线程数量必须仔细的设置,否则冒然增加线程数量只会带来性能的下降。
- 在定制ThreadPoolExecutor时,遵循KISS原则,通常情况下会提供最好的性能。
ForkJoinPool
public class ForkJoinTest {
private double[] d;
private class ForkJoinTask extends RecursiveTask<Integer> {
private int first;
private int last;
public ForkJoinTask(int first, int last) {
this.first = first;
this.last = last;
}
protected Integer compute() {
int subCount;
if (last - first < 10) {
subCount = 0;
for (int i = first; i <= last; i++) {
if (d[i] < 0.5)
subCount++;
}
}
else {
int mid = (first + last) >>> 1;
ForkJoinTask left = new ForkJoinTask(first, mid);
left.fork();
ForkJoinTask right = new ForkJoinTask(mid + 1, last);
right.fork();
subCount = left.join();
subCount += right.join();
}
return subCount;
}
}
public static void main(String[] args) {
d = createArrayOfRandomDoubles();
int n = new ForkJoinPool().invoke(new ForkJoinTask(0, 9999999));
System.out.println("Found " + n + " values");
}
}
public class ThreadPoolTest {
private double[] d;
private class ThreadPoolExecutorTask implements Callable<Integer> {
private int first;
private int last;
public ThreadPoolExecutorTask(int first, int last) {
this.first = first;
this.last = last;
}
public Integer call() {
int subCount = 0;
for (int i = first; i <= last; i++) {
if (d[i] < 0.5) {
subCount++;
}
}
return subCount;
}
}
public static void main(String[] args) {
d = createArrayOfRandomDoubles();
ThreadPoolExecutor tpe = new ThreadPoolExecutor(4, 4, Long.MAX_VALUE, TimeUnit.SECONDS, new LinkedBlockingQueue());
Future[] f = new Future[4];
int size = d.length / 4;
for (int i = 0; i < 3; i++) {
f[i] = tpe.submit(new ThreadPoolExecutorTask(i * size, (i + 1) * size - 1);
}
f[3] = tpe.submit(new ThreadPoolExecutorTask(3 * size, d.length - 1);
int n = 0;
for (int i = 0; i < 4; i++) {
n += f.get();
}
System.out.println("Found " + n + " values");
}
}
在分别使用ForkJoinPool和ThreadPoolExecutor时,它们处理这个问题的时间如下:

for (int i = first; i <= last; i++) {
if (d[i] < 0.5) {
subCount++;
}
for (int j = 0; j < d.length - i; j++) {
for (int k = 0; k < 100; k++) {
dummy = j * k + i; // dummy is volatile, so multiple writes occur
d[i] = dummy;
}
}
}
Parallelization)
Stream<Integer> stream = arrayList.parallelStream();
stream.forEach(a -> {
String symbol = StockPriceUtils.makeSymbol(a);
StockPriceHistory sph = new StockPriceHistoryImpl(symbol, startDate, endDate, entityManager);
});



[Java Performance] 线程及同步的性能之线程池/ThreadPoolExecutors/ForkJoinPool的更多相关文章
- Java 线程与同步的性能优化
本文探讨的主题是,如何挖掘出Java线程和同步设施的最大性能. 1.线程池与ThreadPoolExecutor 1)线程池与ThreadPoolExecutor 线程池的实现可能有所不同,但基本概念 ...
- 【转】线程及同步的性能 - 线程池 / ThreadPoolExecutors / ForkJoinPool
线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自 ...
- 线程及同步的性能 – 线程池/ ThreadPoolExecutors/ ForkJoinPool
线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自 ...
- 牛客网Java刷题知识点之为什么HashMap不支持线程的同步,不是线程安全的?如何实现HashMap的同步?
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
- JAVA多线程提高十一:同步工具Exchanger
Exchanger可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象.Exchanger 可能被视 ...
- 01 语言基础+高级:1-7 异常与多线程_day06 【线程、同步】
day06 [线程.同步] 主要内容 线程 同步 线程状态 一.学习目标 1. 能够描述Java中多线程运行原理 2. 能够使用继承类的方式创建多线程 3. 能够使用实现接口的方式创建多线程 4. 能 ...
- Windows核心编程 第八章 用户方式中线程的同步(上)
第8章 用户方式中线程的同步 当所有的线程在互相之间不需要进行通信的情况下就能够顺利地运行时, M i c r o s o f t Wi n d o w s的运行性能最好.但是,线程很少能够在所有的时 ...
- 308 day06_线程、同步
day06 [线程.同步] 主要内容 线程 同步 线程状态 教学目标 能够描述Java中多线程运行原理 能够使用继承类的方式创建多线程 能够使用实现接口的方式创建多线程 能够说出实现接口方式的好处 ...
- java线程(2)--同步和锁
参考转载:http://rainyear.iteye.com/blog/1734311 http://turandot.iteye.com/blog/1704027 http://www.cnblog ...
随机推荐
- 哈希算法和字典类的定义,DataSet中数据遍历的几种方法
哈希算法的基本操作: 1. 哈希表(HashTable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似 ...
- java中封装的使用方法(工具myeclipse)
封装可以实现属性私有化,将类的属性修饰符由public改为private,如此做者,其他类就无法访问该类中被private修饰的对象,一般我们会使用setter/getter()方法实现对这些对象的访 ...
- “希希敬敬对”队软件工程第九次作业-beta冲刺第四次随笔
“希希敬敬对”队软件工程第九次作业-beta冲刺第四次随笔 队名: “希希敬敬对” 龙江腾(队长) 201810775001 杨希 201810812008 何敬 ...
- C++中的抽象类和接口
1,在 C++ 语言中,并不直接支持面向对象中的抽象类和接口概念,但是 C++ 语言 却可以间接实现这些概念: 2,什么是抽象类: 1,面向对象中的抽象(其实就是分类)概念: 1,在进行面向对象分析时 ...
- vue中给请求来的数据List ,添加属性false 后,赋值不上问题解决办法
data() { return { list:[ // 添加属性fale 后的值 ], // 测试数据 goList:[ { name:'张三', phone:'18621958665' }, { n ...
- 【目录】linux 编程
随笔分类 - linux 编程 Linux编程 24 shell编程(结构化 if [ condition ] 数值比较,字符串比较) 摘要: 一.概述 接着上篇讲的结构化命令,最后讲到了test命令 ...
- 高逼格企业级MySQL数据库备份方案,原来是这样....
很多人,这里说的是运维工程师们,一提到写某某方案,很是头疼.不是上某度一统搜索,就是同样一句话在N个群全部群发一遍:“有没有某某方案,可以共享一下的吗??求助,各位大佬们”,估计十有八九,全部石沉大海 ...
- python实现WordCount(第三次作业)
0x00 注明 合作者:201631062315 201631062310 代码地址:https://gitee.com/c1e4r/word-count2 作业地址:https://edu.cnbl ...
- 使用aop和BindingResult进行参数验证
1.在需要校验的参数名上面添加注解 2.在web层接收参数(参数前面使用@Valid进行标记,后面必须紧跟参数bindingResult,存储参数的错误信息) 3.使用aop进行校验信息统一处理 @C ...
- vue-axios请求
<template> <div> <div v-if="!repoUrl">loding</div> <div v-else& ...