美文网首页Java高级技术
java高并发锁的3种实现

java高并发锁的3种实现

作者: 沐子哈哈哈 | 来源:发表于2017-08-18 14:50 被阅读0次

    初级技巧 - 乐观锁

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

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

    publicObjectget(Objectkey){synchronized(map) {if(map.get(key) ==null) {// set some values}returnmap.get(key);    }  }

    乐观锁的实现:

    publicObjectget(Object key){    Objectval=null;if((val= map.get(key) ==null) {// 当map取值为null时再加锁判断synchronized(map) {if(val= map.get(key) ==null) {// set some value to map...}          }    }returnmap.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()总是返回同一个对象,因此就实现了对同一用户加锁。由于锁的粒度局限于具体用户,使系统获得了最大程度的并发。

    publicvoiddoSomeThing(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加一个锁,伪代码如下:

    Maplocks =newMap();  List lockKeys =newList();for(intnumber :1-10000) {ObjectlockKey =newObject();    lockKeys.add(lockKey);      locks.put(lockKey,newObject());  }publicvoiddoSomeThing(Stringuid){ObjectlockKey = lockKeys.get(uid.hash() % lockKeys.size());Objectlock = locks.get(lockKey);synchronized(lock) {// do something}  }

    大家可以点击加入群:478052716【JAVA高级程序员】里面有Java高级大牛直播讲解知识点 走的就是高端路线(如果你想跳槽换工作 但是技术又不够 或者工作上遇到了瓶颈 我这里有一个JAVA的免费直播课程 讲的是高端的知识点基础不好的误入哟 只要你有1-5年的开发经验可以加群找我要课堂链接 注意:是免费的 没有开发经验误入哦)

    相关文章

      网友评论

        本文标题: java高并发锁的3种实现

        本文链接:https://www.haomeiwen.com/subject/tldarxtx.html