java高并发锁的3种实现
初级技巧 - 乐观锁
乐观锁适合这样的场景:读不会冲突,写会冲突。同时读的频率远大于写。
以下面的代码为例,悲观锁的实现:
Java代码 ![]()
public Object get(Object key) {
synchronized(map) {
if(map.get(key) == null) {
// set some values
}
return map.get(key);
}
}
乐观锁的实现:
Java代码 ![]()
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()总是返回同一个对象,因此就实现了对同一用户加锁。由于锁的粒度局限于具体用户,使系统获得了最大程度的并发。
Java代码 ![]()
public void doSomeThing(String uid) {
synchronized(uid.intern()) {
// ...
}
}
CopyOnWriteMap?
既然说到了“类似于数据库中的行锁的概念”,就不得不提一下MVCC,Java中CopyOnWrite类实现了MVCC。Copy On Write是这样一种机制。当我们读取共享数据的时候,直接读取,不需要同步。当我们修改数据的时候,我们就把当前数据Copy一份副本,然后在这个副本 上进行修改,完成之后,再用修改后的副本,替换掉原来的数据。这种方法就叫做Copy On Write。
但是,,,JDK并没有提供CopyOnWriteMap,为什么?下面有个很好的回答,那就是已经有了ConcurrentHashMap,为什么还需要CopyOnWriteMap?
Fredrik Bromee 写道
I guess this depends on your use case, but why would you need a CopyOnWriteMap when you already have a ConcurrentHashMap?
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加一个锁,伪代码如下:
Java代码 ![]()
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
}
}
java高并发锁的3种实现的更多相关文章
- 构建高性能服务(二)java高并发锁的3种实现
构建高性能服务(二)java高并发锁的3种实现 来源:http://www.xymyeah.com/?p=46 提高系统并发吞吐能力是构建高性能服务的重点和难点.通常review代码时看到sync ...
- java高并发锁的三种实现
提到锁大家会想到Synchronized同步关键字,使用它确实可以解决一切并发问题,但是对于体统吞吐量要求更高,在这里提供了几个小技巧.帮助大家减少锁粒度.提高系统的并发能力 一.乐观锁 试用场景:读 ...
- 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现
[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...
- java高并发系列 - 第12天JUC:ReentrantLock重入锁
java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...
- java高并发系列 - 第17天:JUC中的循环栅栏CyclicBarrier常见的6种使用场景及代码示例
这是java高并发系列第17篇. 本文主要内容: 介绍CyclicBarrier 6个示例介绍CyclicBarrier的使用 对比CyclicBarrier和CountDownLatch Cycli ...
- java高并发系列 - 第31天:获取线程执行结果,这6种方法你都知道?
这是java高并发系列第31篇. 环境:jdk1.8. java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: 在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有 ...
- java高并发系列 - 第11天:线程中断的几种方式
java高并发系列第11篇文章. 本文主要探讨一下中断线程的几种方式. 通过一个变量控制线程中断 代码: package com.itsoku.chat05; import java.util.con ...
- (转载)java高并发:CAS无锁原理及广泛应用
java高并发:CAS无锁原理及广泛应用 版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...
- Java高并发与多线程(四)-----锁
今天,我们开始Java高并发与多线程的第四篇,锁. 之前的三篇,基本上都是在讲一些概念性和基础性的东西,东西有点零碎,但是像文科科目一样,记住就好了. 但是本篇是高并发里面真正的基石,需要大量的理解和 ...
随机推荐
- Java学习笔记——设计模式之一.简单工厂
蜀道之难.难于上青天,侧身西望长咨嗟 --蜀道难 设计模式第一篇,简单工厂. 定义Operation类 package cn.no1.simplefactory; public abstract cl ...
- 弹出输入内容prompt
<script> window.onload = function(){ var oBtn = document.getElementById( "btn" ); oB ...
- Homebrew安装和使用
## homebrew使用1. 安装 `$ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m ...
- Java基础知识二次学习--第三章 面向对象
第三章 面向对象 时间:2017年4月24日17:51:37~2017年4月25日13:52:34 章节:03章_01节 03章_02节 视频长度:30:11 + 21:44 内容:面向对象设计思 ...
- ELK安装与配置
ELK介绍 日志主要包括系统日志.应用程序日志和安全日志.系统运维和开发人员可以通过日志了解服务器软硬件信息.检查配置过程中的错误及错误发生的原因.经常分析日志可以了解服务器的负荷,性能安全性,从而及 ...
- Java集合类从属关系
Java的集合分为了四类:List Set Queue Map,每类都有不同的实现,有基于数组实现的,有基于链表实现的,有基于xx树实现的,不同的实现虽在功能上可以相互替代但都有各自的应用场景,如基于 ...
- JavaScript Style Guide中文总结
github原址:https://github.com/airbnb/javascript 类型*基本类型:包括string.number.boolean.null.undefined,存储的是值本身 ...
- angularjs 水平滚动选中按钮高亮显示 swiper和回到顶部指令的实现ionic
首先安装 swiper npm install --save swiper 或者 bower install --save swiper <link rel="stylesheet&q ...
- python基础入门教程《python入门经典》
第一章 在python中使用数字 1.用变量存储信息 1.1变量的类型 变量,用于存储很多不同的数据类型的信息. 基本数据类型 数据类型 存储内容 示例 integer 整 float 浮点 ...
- 在chrome下鼠标拖动层变文本形状的问题
学JQ也有一段时间了,想自己写个鼠标拖动层移动的效果(很简单,只是为了练习而已)于是就写下了下面的代码 <!DOCTYPE html> <html> <head> ...