- 浏览: 874262 次
- 性别:
- 来自: 北京
博客专栏
-
Java Concurre...
浏览量:97302
文章分类
最新评论
-
guo_guo_guo:
mark
Zookeeper 安装和配置 -
solrer:
xunux 写道windows下,dataDir目录若是用需要 ...
Zookeeper 安装和配置 -
kevlearnjava:
你好 我是按照你的伪集群进行配置的 然后启动第二个和第三个 ...
Zookeeper 安装和配置 -
筑浪小子:
博主应该把vector设定为全局变量,更加清晰一些
线程安全的集合类--Java Concurrency In Practice C05读书笔记 -
tt5753:
jps16437 QuorumPeerMain16663 Zo ...
Zookeeper 安装和配置
[本文是我对Java Concurrency In Practice C11的归纳和总结. 转载请注明作者和出处, 如有谬误, 欢迎在评论中指正. ]
可扩展性和Amdahl's law--阿姆达尔定律
Scalability describes the ability to improve throughput or capacity when additional resources are added. When tuning for performance, the goal is usually to do the same work with less effort. But for scalability, the goal is to do more work with more resources.
Amdahl's law描述随着CPU核心数的增加, 并发程序所能到达的理论上的最大速度. 大多数并发程序包含并发和串行2个部分, 假设某个并发程序串行部分所占的比例为F, CPU核心数为N, 则其最大运行速度为: speedup = 1 / (F + (1 - F) / N), CPU利用率utilization = speedup / N. 由Amdahl's law可知, 假设CPU核心数趋近于无穷, 并发程序理论上的最大速度为1/F.
如果一个并发程序串行部分比例F = 10%, 那么当CPU数N = 10时, 其speedup为5.3, CPU利用率为53%. 当CPU数N增加到100时, speedup为9.2, CPU利用率为9.2%.
Amdahl's law表明, 应用的可扩展性由程序中串行部分所占的比例决定. 在java中, 串行的主要来源为排它锁, 因此, 为增加可扩展性, 可以考虑从以下方面着手:
1. 减少持有锁的时间.
2. 减少锁粒度.
3. 降低申请锁的频率.
4. 以非排它型锁代替排它锁.
减少持有锁的时间
将不必要持有锁的操作从同步代码块中移出可以有效减少持有锁的时间, 尤其是那些需要长时间运行的或者是阻塞的操作. 例如:
public class AttributeStore { private final Map<String, String> attributes = new HashMap<String, String>(); /** * 如果Map中存在name所对应的location, 且location匹配给定的正则表达式时, 返回true. 否则返回false. */ 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); } }
userLocationMatches方法访问了共享变量attributes, 所以需要同步. 但是同步整个userLocationMatches方法是没有必要的, 只需要同步get操作即可:
public boolean userLocationMatches(String name, String regexp) { String key = "users." + name + ".location"; String location = null; synchronized(this) { location = attributes.get(key); } if (location == null) return false; else return Pattern.matches(regexp, location); }
当然, 我们也可以将线程安全的责任委托为Map对象, 这样在AttributeStore类中就不需要做同步了:
public class AttributeStore { /** * 将线程安全的责任委托给ConcurrentHashMap */ private final Map<String, String> attributes = new ConcurrentHashMap<String, String>(); /** * 如果Map中存在name所对应的location, 且location匹配给定的正则表达式时, 返回true. 否则返回false. */ public 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); } }
使用线程安全委托是最好的, 这样我们就不必担心对AttributeStore类的后续修改忘记了加上同步.
减少锁粒度
通过锁的拆分或者分离, 可以减少锁竞争的发生. 例如:
public class ServerStatus { public final Set<String> users = new HashSet<String>(); public final Set<String> queries = new HashSet<String>(); 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); } }
ServerStatus类中所以方法都使用this作为锁. ServerStatus类中存在2个成员users和queries, 使用同一把锁(this)确保2个变量的线程安全意味着增加了锁竞争的发生. 可以将锁拆分为粒度更小的2个锁, 分别保证一个变量的线程安全:
public class ServerStatus { public final Set<String> users = new HashSet<String>(); public final Set<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); } } //... }
一个锁保证一个变量的线程安全可以有效的降低锁竞争的发生. 为了更好的并发性能, 有时甚至使用粒度更小的锁: 使用多个锁保证同一个变量的线程安全. 熟悉ConcurrentHashMap的开发者可能知道, ConcurrentHashMap中使用16个锁保证其线程安全, 这样的机制使得ConcurrentHashMap具有极好的并发性能. 以下的StripedMap是对ConcurrentHashMap的简化:
public class StripedMap { // 使用16个锁保证 StripedMap的线程安全 private static final int N_LOCKS = 16; private final Node[] buckets; private final Object[] locks; private static class Node { // ... } 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); // 使用不同的锁同步不同的bucket 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++) { synchronized (locks[i % N_LOCKS]) { buckets[i] = null; } } } // ... }
以非排它型锁代替排它锁
例如使用读写锁, 不可变对象或者原子量等.
读写锁(ReadWriteLock)支持并发的读操作. 对于读操作频率远大于写操作频率的应用, 读写锁的使用可以带来并发性能的改善.
不可变对象天然具有线程安全, 不需要使用额外的同步.
原子量(如AtomicInteger, AtomicLong等)经常用作计数器, 序列号生成器等.
发表评论
-
状态依赖的类--JCIP C14.1读书笔记
2012-04-11 10:24 2660[本文是我对Java Concurrency In Pract ... -
内置锁和显式锁的区别--JCIP C13读书笔记
2012-04-11 10:17 5774[本文是我对Java Concurrenc ... -
如何避免死锁--JCIPC10读书笔记
2012-04-10 10:08 3140[本文是我对Java Concurrency In Pract ... -
task与execution--JCIPC08读书笔记
2012-04-09 10:34 2396[本文是我对Java Concurrency In Pract ... -
配置ThreadPoolExecutor
2012-04-09 10:34 6222[本文是我对Java Concurrency In Pract ... -
停止基于线程的Service--JCIP7.2读书笔记
2012-04-06 10:28 2331[本文是我对Java Concurrency In Pract ... -
处理不可中断的阻塞-JCIP7.1读书笔记
2012-04-06 10:23 5698[本文是我对Java Concurrenc ... -
处理InterruptedException异常--JCIP7.1读书笔记
2012-04-05 14:08 6120[本文是我对Java Concurrency In Pract ... -
中断线程--JCIP7.1读书笔记
2012-04-05 14:03 2593[本文是我对Java Concurrency In Pract ... -
改善并发性能--JCIP6.3读书笔记
2012-04-02 11:51 2555[本文是我对Java Concurrency In Pr ... -
Executor--JCIP C06读书笔记
2012-04-02 09:28 2859[本文是我对Java Concurrency In Pract ... -
设计高效的线程安全的缓存--JCIP5.6读书笔记
2012-04-01 22:49 5856[本文是我对Java Concurrency In Pract ... -
synchronizer--JCIP5.5读书笔记
2012-04-01 22:44 2343[本文是我对Java Concurrency In Pract ... -
使用BlockingQueue构建生产者消费者模式--JCIP5.3读书笔记
2012-03-31 17:32 4604[本文是我对Java Concurrency In Pract ... -
ConcurrentHashMap和CopyOnWriteArrayList--Java Concurrency In Practice C05读书笔记
2012-03-31 11:27 4038[本文是我对Java Concurrenc ... -
线程安全的集合类--Java Concurrency In Practice C05读书笔记
2012-03-28 18:26 14242[本文是我对Java Concurrency In Pract ... -
利用对象限制和委托构建线程安全的类--Java Concurrency In Practice C04读书笔记
2012-03-27 18:23 3827[本文是我对Java Concurrency In Pract ... -
变量可见性和volatile, this逃逸, 不可变对象, 以及安全公开--Java Concurrency In Practice C03读书笔记
2012-03-26 21:55 12565[本文是我对Java Concurrency In Pract ... -
变量可见性和volatile, this逃逸, 不可变对象, 以及安全公开--Java Concurrency In Practice C02读书笔记
2012-03-26 21:53 2[本文是我对Java Concurrency In Pract ... -
Race condition--Java Concurrency In Practice C02读书笔记
2012-03-26 10:17 4990[本文是我对Java Concurrenc ...
相关推荐
标题 "cpp-简洁易用的C11网络库支持单机千万并发连接" 提到的是一个基于C++11标准的网络库,该库旨在提供高效且易于使用的网络服务器框架,能够支持高并发连接,最高可达千万级别的并发连接。这在处理大量并发请求的...
在SQL2005的读书笔记中,我们探讨的是微软的SQL Server 2005这一强大数据库管理系统的关键概念和技术。SQL(Structured Query Language)是用于管理关系数据库的标准语言,而SQL Server 2005作为其一个版本,提供了...
list原始代码实践中的Java并发-代码清单 创建时间:2020年11月9日晚上11:13网址: 由Brian Goetz和Tim Peierls在JCP JSR-166专家组成员的协助下撰写,并已发布到公共领域,如所解释。 请注意,Creative Commons不再...
《java并发编程实战》读书笔记-第2章-线程安全性,脑图形式,使用xmind8制作 包括引言、线程安全性定义、原子性、加锁机制、使用锁保护状态、活跃性与性能等内容
本文将基于文档《Java并发编程与高并发解决方案-学习笔记***.pdf》中提供的内容,来详细阐述并发编程和高并发的基本概念、CPU多级缓存与缓存一致性、以及Java内存模型。 ### 并发与高并发概念 在现代多线程编程中...
这种架构允许开发者将游戏对象的不同方面(如物理、动画、AI等)分离为独立的组件,从而提高了代码的复用性和可扩展性。开发者可以根据需求自由组合组件,创建出复杂的游戏实体,同时保持代码的清晰和模块化。 在...
5. 正确性和线程安全性:编写并发应用程序的步骤包括保证程序正确性和性能测试,如果需要,再对程序进行优化。无状态的类天生就是线程安全的。 6. 竞态条件和原子操作:竞态条件是由于线程执行顺序的不确定性导致...
《java并发编程实战》读书笔记-第3章-对象的共享,脑图形式,使用xmind8制作 包括可见性、发布与逸出、线程封闭、不可变性、安全发布等内容
《java并发编程实战》读书笔记-第3章-对象的共享,脑图形式,使用xmind8制作 包括线程安全类设计、实例封闭、线程安全性委托、现有线程安全类中添加功能和文档化同步策略等内容
读书笔记:《实战Java高并发程序设计》读书笔记
《java并发编程实战》读书笔记-第3章-对象的共享,脑图形式,使用xmind8制作 包括同步容器类、并发容器类、阻塞队列和生产者消费者模式、阻塞和中断方法、同步工具类。最后是构建高效且可伸缩的结果缓存
Java并发编程与高并发解决方案是开发高性能应用的关键技术。在基础篇中,主要涉及以下几个重要知识点: 1. **并发编程基础** - **并发**:并发是指在一个时间段内,多个线程交替执行,使得系统看起来像是同时处理...
《实战Java高并发程序设计》第二版是一本深入探讨Java多线程和并发编程的书籍。这本书涵盖了Java并发编程的核心概念和技术,旨在帮助开发者在实际项目中高效地处理高并发场景。随书附带的代码提供了丰富的示例,以便...
管理微信小程序 wx.request 方法的并发数,解决请求数大于 10 时,直接不请求的问题。如果需要 wx.request 方法支持 Promise,可以使用 wx-promise-request 库哦。 下载 由于小程序不支持 npm,所以直接右键保存 ...
读书笔记:实战Java高并发程序设计学习笔记
读书笔记:《实战Java高并发程序设计》学习笔记
读书笔记:《实战 Java高并发程序设计》学习笔记
读书笔记:java高并发程序设计实战
读书笔记:实战java高并发程序设计