构建高性能服务(二)java高并发锁的3种实现
构建高性能服务(二)java高并发锁的3种实现
提高系统并发吞吐能力是构建高性能服务的重点和难点。通常review代码时看到synchronized是我都会想一想,这个地方可不可以优化。使用synchronized使得并发的线程变成顺序执行,对系统并发吞吐能力有极大影响,我的博文 http://maoyidao.iteye.com/blog/1149015 介绍了可以从理论上估算系统并发处理能力的方法。
那么对于必须使用synchronized的业务场景,这里提供几个小技巧,帮助大家减小锁粒度,提高系统并发能力。
初级技巧 - 乐观锁
乐观锁适合这样的场景:读不会冲突,写会冲突。同时读的频率远大于写。
以下面的代码为例,悲观锁的实现:
- public Object get(Object key) {
- synchronized(map) {
- if(map.get(key) == null) {
- // set some values
- }
- return map.get(key);
- }
- }
乐观锁的实现:
- public Object get(Object key) {
- Object val = null;
- if((val = map.get(key) == null) {
- // 当map取值为null时再加锁判断
- synchronized(map) {
- if(val = map.get(key) == null) {
- // set some value to map...
- }
- }
- }
- return map.get(key);
- }
中级技巧 - String.intern()
乐观锁不能很好解决大量写冲突问题,但是如果很多场景下,锁实际上只是针对某个用户或者某个订单。比如一个用户必须先创建session,才能进行后面的操作。但是由于网络原因,创建用户session的请求和后续请求几乎同时达到,而并行线程可能会先处理后续请求。一般情况,需要对用户sessionMap加锁,比如上面的乐观锁。在这种场景下,可以讲锁限定到用户本身上,即从原来的
lock.lock();
int num=storage.get(key);
storage.set(key,num+1);
lock.unlock();
更改为:
lock.lock(key);
int num=storage.get(key);
storage.set(key,num+1);
lock.unlock(key);
这个比较类似于数据库表锁和行锁的概念,显然行锁的并发能力比表锁高很多。
使用String.inter()是这种思路的一种具体实现。类 String 维护一个字符串池。 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。可见,当String相同时,String.intern()总是返回同一个对象,因此就实现了对同一用户加锁。由于锁的粒度局限于具体用户,使系统获得了最大程度的并发。
- public void doSomeThing(String uid) {
- synchronized(uid.intern()) {
- // ...
- }
- }
CopyOnWriteMap?
既然说到了“类似于数据库中的行锁的概念”,就不得不提一下MVCC,Java中CopyOnWrite类实现了MVCC。Copy On Write是这样一种机制。当我们读取共享数据的时候,直接读取,不需要同步。当我们修改数据的时候,我们就把当前数据Copy一份副本,然后在这个副本 上进行修改,完成之后,再用修改后的副本,替换掉原来的数据。这种方法就叫做Copy On Write。
但是,,,JDK并没有提供CopyOnWriteMap,为什么?下面有个很好的回答,那就是已经有了ConcurrentHashMap,为什么还需要CopyOnWriteMap?
For a plain lookup table with many readers and only one or few updates it is a good fit.
Compared to a copy on write collection:
Read concurrency:
Equal to a copy on write collection. Several readers can retrieve elements from the map concurrently in a lock-free fashion.
Write concurrency:
Better concurrency than the copy on write collections that basically serialize updates (one update at a time). Using a concurrent hash map you have a good chance of doing several updates concurrently. If your hash keys are evenly distributed.
If you do want to have the effect of a copy on write map, you can always initialize a ConcurrentHashMap with a concurrency level of 1.
高级技巧 - 类ConcurrentHashMap
String.inter()的缺陷是类 String 维护一个字符串池是放在JVM perm区的,如果用户数特别多,导致放入字符串池的String不可控,有可能导致OOM错误或者过多的Full GC。怎么样能控制锁的个数,同时减小粒度锁呢?直接使用Java ConcurrentHashMap?或者你想加入自己更精细的控制?那么可以借鉴ConcurrentHashMap的方式,将需要加锁的对象分为多个bucket,每个bucket加一个锁,伪代码如下:
- Map locks = new Map();
- List lockKeys = new List();
- for(int number : 1 - 10000) {
- Object lockKey = new Object();
- lockKeys.add(lockKey);
- locks.put(lockKey, new Object());
- }
- public void doSomeThing(String uid) {
- Object lockKey = lockKeys.get(uid.hash() % lockKeys.size());
- Object lock = locks.get(lockKey);
- synchronized(lock) {
- // do something
- }
- }
关于高性能缓存的设计,请参考构建高性能服务系列之一:http://www.xymyeah.com/?p=10
更多http://www.xymyeah.com/?p=46
相关文章
- Java 异常错误 (Ljava/lang/String;)L java/lang/String;「建议收藏」
- java工具类-Java对象转换成Map
- Java中byte类型的范围「建议收藏」
- java笔试题_一道简单的 Java 笔试题,但值得很多人反思
- java启动器_JAVA基础:Java 启动器如何查找类
- c语言与java哪个更好_c语言和java哪个好?[通俗易懂]
- java标识符是什么_Java 标识符「建议收藏」
- xml格式化 java_Java XML格式化程序
- 基于DB4O的Java Map
- java 阶乘算法_Java 实现阶乘算法
- java 随机数算法_Java随机数算法原理与实现方法实例详解
- Java把string转json格式_java实体类转json字符串
- 【SC随笔】Java测试mutator方法的注意点
- ringbuffer java例子_Java RingBuffer.publish方法代碼示例「建议收藏」
- java url加密_Java实现url加密处理的方法示例
- Java并发的CAS原理详解[通俗易懂]
- Java—java.util.calendar类详解「建议收藏」
- 三面“有赞”Java岗斩获offer:Spring+JVM+并发锁+分布式+算法
- 甲骨文Java语言架构师:虚拟线程将会深刻影响大规模Java应用的并发机制
- java并发编程(1):Java多线程-基本线程类-基础知识复习笔记
- Java高并发高性能分布式框架从无到有微服务架构设计详解架构师
- Java 加载Properties文件的六种方式详解编程语言
- java压缩与解压(Java.util.zip)详解编程语言
- Java基础-String和StringBuilder类型详解编程语言
- Java并发编程之ReentrantLock源码解析详解编程语言
- 时间设置使用Java设置Redis数据库的过期时间(redisjava过期)
- MySQL与Java的结合:实现强大的数据持久化功能(mysql与java)
- 实现高并发:Java利用Redis秒杀成功(java秒杀redis)
- Java锁表与Oracle数据库协调实现数据安全(java锁表oracle)
- Java更新提升Oracle软件性能(java更新oracle)
- Java存入Oracle数据库实现快速高效的数据存储(java存入oracle)
- Redis面试中Java相关技术面试题汇总(redis面试题java)
- 并发Redis锁保障Java并发性(redis锁实现java)
- Java环境变量的设置方法(图文教程)
- java实现倒序读取文件功能示例分享