java并发编程(4)性能与可伸缩性
性能与可伸缩性
一、Amdahl定律
1.问题和资源的关系
在某些问题中,资源越多解决速度越快;而有些问题则相反:

注意:每个程序中必然有串行的部分,而合理的分析出串行和并行的部分对程序的影响极大;串行部分占比和多核执行效率之间是指数级别的关系
2.ConcurrentLinkedQueue
在多核环境中,这个线程安全的队列比通过synchronizedList生成的队列速度要快很多
可以说:concurrent中提供的类,比通过方法生成的线程安全类速度要快
二、线程开销
由于多线程有开销:所以使用多线程必须保证性能的提升>并发的开销
上下文切换的开销
内存同步的开销
三、减少锁的竞争
1.减少锁持有时间:缩小锁的范围
private final Map<String, String> attributes = new HashMap<String, String>(); //整个方法上锁
public synchronized boolean userLocationMatches(String name, String regexp) {
String key = "users." + name + ".location";
String location = attributes.get(key);
if (location == null)
return false;
else
return Pattern.matches(regexp, location);
} public boolean userLocationMatches(String name, String regexp) {
String key = "users." + name + ".location";
String location;
//只针对可变状态上锁
synchronized (this) {
location = attributes.get(key);
}
if (location == null)
return false;
else
return Pattern.matches(regexp, location);
}
2.降低锁的请求频率:锁分解、锁分段...
锁分解:将一个锁分解为多个锁如:无需在一个原子操作中更新多个状态变量,每个状态变量却用的是同一个类锁,就没必要,每个不相干的状态变量的使用自己的锁就行
public class ServerStatusBeforeSplit {
public final Set<String> users;
public final Set<String> queries;
public ServerStatusBeforeSplit() {
users = new HashSet<String>();
queries = new HashSet<String>();
}
//每个方法使用 当前class实例锁,类似于synchronized(this),不管是否是操作同一共享状态
public synchronized void addUser(String u) {
users.add(u);
}
public synchronized void addQuery(String q) {
queries.add(q);
}
public synchronized void removeUser(String u) {
users.remove(u);
}
public synchronized void removeQuery(String q) {
queries.remove(q);
}
}
public class ServerStatusAfterSplit {
public final Set<String> users;
public final Set<String> queries;
//操作同一 状态的方法 使用相同的锁
public ServerStatusAfterSplit() {
users = new HashSet<String>();
queries = new HashSet<String>();
}
public void addUser(String u) {
synchronized (users) {
users.add(u);
}
}
public void addQuery(String q) {
synchronized (queries) {
queries.add(q);
}
}
public void removeUser(String u) {
synchronized (users) {
users.remove(u);
}
}
public void removeQuery(String q) {
synchronized (users) {
queries.remove(q);
}
}
}
锁分段:如将map桶分成不同的段,每个段都有一个锁,这样,在执行某些操作如get,就可以持有不同的锁从而提高并发效率,当然有些操作需要同时持有容器所有段的锁如clear等
//Map分段锁实现
public class StripedMap {
// Synchronization policy: buckets[n] guarded by locks[n%N_LOCKS]
private static final int N_LOCKS = 16; //锁数量
private final Node[] buckets; //容器桶
private final Object[] locks; //同步监听器对象数组
private static class Node {
Node next;
Object key;
Object value;
} public StripedMap(int numBuckets) {
buckets = new Node[numBuckets];
locks = new Object[N_LOCKS];
for (int i = 0; i < N_LOCKS; i++)
locks[i] = new Object();
}
private final int hash(Object key) {
return Math.abs(key.hashCode() % buckets.length);
}
public Object get(Object key) {
int hash = hash(key);
//获取当前 key对应的index区域的锁,只获取了一个锁
synchronized (locks[hash % N_LOCKS]) {
for (Node m = buckets[hash]; m != null; m = m.next)
if (m.key.equals(key))
return m.value;
}
return null;
}
public void clear() {
for (int i = 0; i < buckets.length; i++) {
//获取 每个i对应的锁,就是获取了整个容器所有的分段锁
synchronized (locks[i % N_LOCKS]) {
buckets[i] = null;
}
}
}
}
3.避免热点域
热点资源的锁竞争激烈,导致的性能问题
4.替代独占锁
如:读-写锁:读读可并行,来防止独占;使用原子状态量;使用并发容器;使用不可变对象等
5.减少上下文切换
任务在阻塞于非阻塞的状态中切换,就类似于一次上下文切换
如:日志,日志的打印和IO操作会导致大量的阻塞和释放,导致性能问题
java并发编程(4)性能与可伸缩性的更多相关文章
- Java并发编程:性能、扩展性和响应
1.介绍 本文讨论的重点在于多线程应用程序的性能问题.我们会先给性能和扩展性下一个定义,然后再仔细学习一下Amdahl法则.下面的内容我们会考察一下如何用不同的技术方法来减少锁竞争,以及如何用代码来实 ...
- 《Java并发编程实战》/童云兰译【PDF】下载
<Java并发编程实战>/童云兰译[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062521 内容简介 本书深入浅出地介绍了Jav ...
- java并发编程——通过ReentrantLock,Condition实现银行存取款
java.util.concurrent.locks包为锁和等待条件提供一个框架的接口和类,它不同于内置同步和监视器.该框架允许更灵活地使用锁和条件,但以更难用的语法为代价. Lock 接口 ...
- Java并发编程面试题 Top 50 整理版
本文在 Java线程面试题 Top 50的基础上,对部分答案进行进行了整理和补充,问题答案主要来自<Java编程思想(第四版)>,<Java并发编程实战>和一些优秀的博客,当然 ...
- Java并发编程75道面试题及答案
1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程(Daemon)和用户线程(User). 任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon( ...
- [Java并发编程(四)] Java volatile 的理论实践
[Java并发编程(四)] Java volatile 的理论实践 摘要 Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 ...
- Java并发编程(六)volatile关键字解析
由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识. 一.内存模型的相关概念 Java内存模型规定所有的变量都是存在 ...
- java并发编程系列七:volatile和sinchronized底层实现原理
一.线程安全 1. 怎样让多线程下的类安全起来 无状态.加锁.让类不可变.栈封闭.安全的发布对象 2. 死锁 2.1 死锁概念及解决死锁的原则 一定发生在多个线程争夺多个资源里的情况下,发生的原因是 ...
- Java并发编程73道面试题及答案 —— 面试稳了
今天主要整理一下 Java 并发编程在面试中的常见问题,希望对需要的读者有用. 1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程(Daemon)和用户线程(User). 任 ...
- 【Java并发编程二】同步容器和并发容器
一.同步容器 在Java中,同步容器包括两个部分,一个是vector和HashTable,查看vector.HashTable的实现代码,可以看到这些容器实现线程安全的方式就是将它们的状态封装起来,并 ...
随机推荐
- [C#学习笔记]你真的理解拆箱装箱吗?
学习一项新知识的时候,最好的方法就是去实践它. 前言 <CLR via C#>这本神书真的是太有意思了!没错我的前言就是这个. 装箱 首先来看下,下面这段代码 可以看到,每次循环迭代都会初 ...
- 再编写代码中报错:CS8107 C# 7.0 中不支持功能“xxxxxx”。请使用 7.1 或更高的语言版本。
解决方法:项目右键属性 ---> 生成 ---> 找到最下面的高级按钮,点击高级按钮 ---> 常规 ---> 语言版本 ---> 选择 C#最新次要版本,或者比当前版本 ...
- 注意力机制(Attention Mechanism)应用——自然语言处理(NLP)
近年来,深度学习的研究越来越深入,在各个领域也都获得了不少突破性的进展.基于注意力(attention)机制的神经网络成为了最近神经网络研究的一个热点,下面是一些基于attention机制的神经网络在 ...
- kolla-ansible 重新部署 ceph-mon 组件
1.备份数据 [root@controller ~]# mv /var/lib/docker/volumes/ceph_mon /var/lib/docker/volumes/ceph_backup/ ...
- Win10桌面图标无法拖动
1.右键桌面>查看>取消自动排列 2.桌面多按几次Esc 3.gpedit.msc “用户配置/管理模板/Windows组件/任务计划程序/禁止拖放>改为未配置
- 使用deque模块固定队列长度,用headq模块来查找最大或最小的N个元素以及实现一个优先级排序的队列
一. deque(双端队列) 1. 使用 deque(maxlen=N)会新建一个固定大小的队列.当新的元素加入并且这个队列已满的时候,最老的元素会自动被移除掉 >>> from c ...
- day 13 课后作业
# -*- coding: utf-8 -*-# @Time : 2019/1/7 18:00# @Author : Endless-cloud# @Site : # @File : day 13 课 ...
- 通过UIColor转换为UIImage
+ (UIImage *)createImageWithColor:(UIColor *)color { CGRect rect=CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); ...
- C#-进制转换、基础语句、语句的总结与练习——★for循环:九九乘法表、三角形、菱形★
//for循环嵌套练习——打一个九九乘法表 ; i <= ; i++) { ; j <= i; j++) { Console.Write(j + "×" + i + & ...
- QuantLib 金融计算——收益率曲线之构建曲线(1)
目录 QuantLib 金融计算--收益率曲线之构建曲线(1) YieldTermStructure DiscountCurve DiscountCurve 对象的构造 ZeroCurve ZeroC ...