初级技巧 - 乐观锁

乐观锁适合这样的场景:读不会冲突,写会冲突。同时读的频率远大于写。

以下面的代码为例,悲观锁的实现:

Java代码  

  1. public Object get(Object key) {

  2. synchronized(map) {

  3. if(map.get(key) == null) {

  4. // set some values

  5. }

  6. return map.get(key);

  7. }

  8. }

乐观锁的实现:

Java代码  

  1. public Object get(Object key) {

  2. Object val = null;

  3. if((val = map.get(key) == null) {

  4. // 当map取值为null时再加锁判断

  5. synchronized(map) {

  6. if(val = map.get(key) == null) {

  7. // set some value to map...

  8. }

  9. }

  10. }

  11. return map.get(key);

  12. }

中级技巧 - 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代码  

  1. public void doSomeThing(String uid) {

  2. synchronized(uid.intern()) {

  3. // ...

  4. }

  5. }

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代码  

    1. Map locks = new Map();

    2. List lockKeys = new List();

    3. for(int number : 1 - 10000) {

    4. Object lockKey = new Object();

    5. lockKeys.add(lockKey);

    6. locks.put(lockKey, new Object());

    7. }

    8. public void doSomeThing(String uid) {

    9. Object lockKey = lockKeys.get(uid.hash() % lockKeys.size());

    10. Object lock = locks.get(lockKey);

    11. synchronized(lock) {

    12. // do something

    13. }

    14. }

    15. 参考更多免费教程请加入Dubbo技术交流:548209960
      Java高并发高可用架构:632103578

java高并发锁的3种实现的更多相关文章

  1. 构建高性能服务(二)java高并发锁的3种实现

    构建高性能服务(二)java高并发锁的3种实现 来源:http://www.xymyeah.com/?p=46   提高系统并发吞吐能力是构建高性能服务的重点和难点.通常review代码时看到sync ...

  2. java高并发锁的三种实现

    提到锁大家会想到Synchronized同步关键字,使用它确实可以解决一切并发问题,但是对于体统吞吐量要求更高,在这里提供了几个小技巧.帮助大家减少锁粒度.提高系统的并发能力 一.乐观锁 试用场景:读 ...

  3. 【实战Java高并发程序设计6】挑战无锁算法:无锁的Vector实现

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  4. java高并发系列 - 第12天JUC:ReentrantLock重入锁

    java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...

  5. java高并发系列 - 第17天:JUC中的循环栅栏CyclicBarrier常见的6种使用场景及代码示例

    这是java高并发系列第17篇. 本文主要内容: 介绍CyclicBarrier 6个示例介绍CyclicBarrier的使用 对比CyclicBarrier和CountDownLatch Cycli ...

  6. java高并发系列 - 第31天:获取线程执行结果,这6种方法你都知道?

    这是java高并发系列第31篇. 环境:jdk1.8. java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: 在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有 ...

  7. java高并发系列 - 第11天:线程中断的几种方式

    java高并发系列第11篇文章. 本文主要探讨一下中断线程的几种方式. 通过一个变量控制线程中断 代码: package com.itsoku.chat05; import java.util.con ...

  8. (转载)java高并发:CAS无锁原理及广泛应用

    java高并发:CAS无锁原理及广泛应用   版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...

  9. Java高并发与多线程(四)-----锁

    今天,我们开始Java高并发与多线程的第四篇,锁. 之前的三篇,基本上都是在讲一些概念性和基础性的东西,东西有点零碎,但是像文科科目一样,记住就好了. 但是本篇是高并发里面真正的基石,需要大量的理解和 ...

随机推荐

  1. 前端魔法堂:onsubmit和submit事件处理函数怎么不生效呢?

    前言  最近在用Polymer增强form,使其支持表单的异步提交,但发现明明订阅了onsubmit和submit事件,却怎么也触发不了.下面我们将一一道来. 提交表单的方式 表单仅含一个以下的元素时 ...

  2. hdu1068 Girls and Boys 二分匹配

    题目链接: 二分匹配的应用 求最大独立集 最大独立集等于=顶点数-匹配数 本体中由于男孩和女孩的学号是不分开的,所以匹配数应是求得的匹配数/2 代码: #include<iostream> ...

  3. Oracle 12C 新特性之move (非分区表)table online

    以前版本中move table不能够online, move 会引rowid改变使对应的索引失效. 12c 中 alter table move online不会对新事务阻塞同时会自动的维护索引的有效 ...

  4. TCP协议简介

    1.TCP协议的特点 TCP是面向连接的运输层协议 每一条TCP连接只能有两个端点.TCP只能进行点对点通信 TCP提供可靠交付的服务.通过TCP连接传输的数据,无差错.不丢失.不重复.并且按序到达 ...

  5. 消息队列RabbitMQ与Spring集成

    1.RabbitMQ简介 RabbitMQ是流行的开源消息队列系统,用erlang语言开发.RabbitMQ是AMQP(高级消息队列协议)的标准实现. 官网:http://www.rabbitmq.c ...

  6. 开涛spring3(9.4) - Spring的事务 之 9.4 声明式事务

    9.4  声明式事务 9.4.1  声明式事务概述 从上节编程式实现事务管理可以深刻体会到编程式事务的痛苦,即使通过代理配置方式也是不小的工作量. 本节将介绍声明式事务支持,使用该方式后最大的获益是简 ...

  7. 开涛spring3(5.1&5.2) - Spring表达式语言 之 5.1 概述 5.2 SpEL基础

    5.1  概述 5.1.1  概述 Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”,类似于Struts2x中使用的OGNL表达式语言,能在运行 ...

  8. stm32之IIC通信协议

    I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS公司开发用于连接微控制器及其外围设备. 它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数 ...

  9. springboot thymeleaf和shiro标签整合

    这里用的是 thymeleaf 2.x版本的 添加依赖 <dependency> <groupId>com.github.theborakompanioni</group ...

  10. 汽车Vin码识别——可以嵌入到手机里的新OCR识别技术

              汽车Vin码识别(车架号识别),顾名思义,就是识别汽车的Vin码(车架号),汽车Vin码识别(车架号识别)利用的是OCR识别技术,支持视频流获取图像,自动触发识别,另外汽车Vin码 ...