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的实现代码,可以看到这些容器实现线程安全的方式就是将它们的状态封装起来,并 ...
随机推荐
- String,Json,Map之间的转化
前提条件: 1)String的格式是map或json类型的 ; 2)在JAVA中使用JSON需要引入 org.json 包 String >>Json JSONObject jsonObj ...
- java学习笔记—标准连接池的实现(27)
javax.sql.DataSource. Java.sql.* DataSource 接口由驱动程序供应商实现.共有三种类型的实现: 基本实现 - 生成标准的 Connection 对象 – 一个D ...
- ping使用
while read line do ip=`echo $line | awk '{print $2}' ` -i $ip ];then echo $line | tee -a b fi
- 2018-2019-2 20165219《网络对抗技术》Exp4 恶意代码分析
基础问题回答 实验目的 监控系统的运行状态,看有没有可疑的程序在运行 分析一个恶意软件,就分析Exp2或Exp3中生成后门软件:分析工具尽量使用原生指令或sysinternals,systracer套 ...
- centos7安装nginx(自定义安装文件夹)
一.安装所需要的依赖软件 1.gcc:nginx编译依赖gcc环境 #yum install gcc-c++ 2.pcre:(Perl Compatible Regular Expressions)是 ...
- isset()、empty()、is_NULL()的区别
1,isset():变量不存在,或变量为null,返回false,否则返回true: 2,empty():变量不存在,或变量为null,返回true,另外"".0."0& ...
- java使用Redis5--分布式存储
Redis实现分布式存储的方法主要是采用一致性哈稀分片(Shard),将不同的key分配到不同的redis server上,达到横向扩展的目的. package redis; import java. ...
- mxonline实战5,用户注册的验证码
github对应地址:验证码好麻烦 一. 安装 配置 1. pip install django-simple-captcha 2. add captcha to the INSTAL ...
- Unicode字符串索引
一.目标 在通讯录中,我们有很多联系人,需要把这些联系人进行索引.对于每一个索引项对应的若干字符串,需要对这些字符串进行排序. 需要解决两个问题: 如何确定某个汉字应该被哪个字符索引? 某个索引项对应 ...
- 51.RocketMQ 顺序消费
大部分的员工早上的心情可能不会很好,因为这时想到还有很多事情要做,压力会大点,一般到下午4点左右,状态会是一天中最好的,因为这时大部分的工作做得差不多了,又快要下班了,当然也不是绝对.要注意记录各下属 ...