[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 ...
随机推荐
- 蓝桥杯:排它平方数-java
问题描述: 小明正看着 203879 这个数字发呆.原来,203879 * 203879 = 41566646641这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同 ...
- 电脑同时安装python2和python3 ,默认使用python3
python3环境变量放在python2前面: 此电脑--属性--高级系统设置--高级--环境变量--系统变量--Path--编辑 D:\Python36\Scripts;D:\Python36;C: ...
- Codeforces 1140C(贪心+堆)
题面 传送门 题意: 给出长度为n的序列b,t,定义一个子序列的值为\(\min\{ b_i\} \times \sum t_i\),求所有子序列中值最大的一个,输出最大值 分析 假如固定某个b[i] ...
- LOGO有哪几种常规设计思路?
Logo设计的思路多种多样,但是我个人从Logo设计的历史上,大致可以归纳出五种常规思路,思路的名称是自己编的,仅供大家参考.而列举的这些思路背后,都是有着各自的时代背景的. 先从历史最悠久的一种设计 ...
- 【知识强化】第六章 查找 6.4 散列(Hash)表
本节课我们来学习一种新的查找方式叫做散列查找.什么是散列查找呢?在学习散列查找之前,一定要介绍一个基本概念就是散列表.那么学习散列表之前我们先来回忆一下之前所学习过的所有查找方式,那么无论是顺序查找还 ...
- 【转载】linux查看端口状态相关命令
具体命令移步:https://www.cnblogs.com/cxbhakim/p/9353383.html
- SET CONSTRAINTS - 设置当前事务的约束模式
SYNOPSIS SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE } DESCRIPTION 描述 SET CONSTRAI ...
- centos7下的Firewalld
一.介绍 防火墙守护 firewalld 服务引入了一个信任级别的概念来管理与之相关联的连接与接口.它支持 ipv4 与 ipv6,并支持网桥,采用 firewall-cmd (command) 或 ...
- 【leetcode】940. Distinct Subsequences II
题目如下: Given a string S, count the number of distinct, non-empty subsequences of S . Since the result ...
- datagrid+toolbar 不分页 显示
1 新建DataGrid.js文件 /*** * * *el: table id * ***/ function showDataGrid(el) { $(el).datagrid({ title: ...