细粒度锁:
java中的几种锁:synchronized,ReentrantLock,ReentrantReadWriteLock已基本可以满足编程需求,但其粒度都太大,同一时刻只有一个线程能进入同步块,这对于某些高并发的场景并不适用。比如银行客户a向b转账,c向d转账,假如这两个线程并发,代码其实不需要同步。但是同时有线程3,e向b转账,那么对b而言必须加入同步。这时需要考虑锁的粒度问题,即细粒度锁。
网上搜寻了一些关于java细粒度锁的介绍文章,大部分是提供思路,比如乐观锁,String.intern()和类ConcurrentHashMap,本人对第三种比较感兴趣,为此研究了下ConcurrentHashMap的源码。基于ConcurrentHashMap设计细粒度大志思路如下:
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 } }
具体实现如下:
public class LockPool { //用户map private static ConcurrentHashMapuserMap=new ConcurrentHashMap (); //用户金额map private static ConcurrentHashMap moneyMap=new ConcurrentHashMap (); public static void main(String[] args) { LockPool lockPool=new LockPool(); ExecutorService service = Executors.newCachedThreadPool(); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u1")); service.execute(lockPool.new Boss("u1")); service.execute(lockPool.new Boss("u3")); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u3")); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u2")); service.execute(lockPool.new Boss("u4")); service.execute(lockPool.new Boss("u2")); service.shutdown(); } class Boss implements Runnable{ private String userId; Boss(String userId){ this.userId=userId; } @Override public void run() { addMoney(userId); } } public static void addMoney(String userId){ Object obj=userMap.get(userId); if(obj==null){ obj=new Object(); userMap.put(userId,obj); } //obj是与具体某个用户绑定,这里应用了synchronized(obj)的小技巧,而不是同步当前整个对象 synchronized (obj) { try { System.out.println("-------sleep4s--------"+userId); Thread.sleep(4000); System.out.println("-------awake----------"+userId); } catch (InterruptedException e) { e.printStackTrace(); } if(moneyMap.get(userId)==null){ moneyMap.put(userId,1); } else{ moneyMap.put(userId, moneyMap.get(userId)+1); } System.out.println(userId+"-------moneny----------"+moneyMap.get(userId)); } } }
测试结果:
-------sleep4s--------u2 -------sleep4s--------u1 -------sleep4s--------u3 -------sleep4s--------u4 -------awake----------u2 -------awake----------u3 -------awake----------u1 u2-------moneny----------1 u1-------moneny----------1 -------sleep4s--------u1 u3-------moneny----------1 -------sleep4s--------u2 -------sleep4s--------u3 -------awake----------u4 u4-------moneny----------1 -------awake----------u1 u1-------moneny----------2 -------awake----------u3 u3-------moneny----------2 -------awake----------u2 u2-------moneny----------2 -------sleep4s--------u2 -------awake----------u2 u2-------moneny----------3 -------sleep4s--------u2 -------awake----------u2 u2-------moneny----------4 -------sleep4s--------u2 -------awake----------u2 u2-------moneny----------5 -------sleep4s--------u2 -------awake----------u2 u2-------moneny----------6
测试结果来看,只有相同userId的线程才会互斥,同步等待;不同userId的线程没有同步
火柴人绳索英雄2无限金币版 (Stickman Rope Hero 2)安卓版v2.2v3.4.2
下载奥特曼之格斗超人内测版本 安卓最新版v11.0.0
下载奥特曼之格斗超人百度版 安卓版v11.0.0
下载奥特曼之格斗超人4399游戏盒版 最新安卓版v11.0.0
下载德凯奥特曼D闪光剑模拟器 安卓版v1.0
德凯奥特曼D闪光剑模拟器是一个非常有趣的奥特曼变身模拟器,可
亚刻觉醒器 安卓版v1.1
亚刻觉醒器模拟器是一个非常有趣的奥特曼变身模拟器,为喜欢亚刻
海上餐厅无限金币版 v1.0
海上餐厅免广告版是游戏的破解版本,在该版本中为玩家去除了广告
阿西美女室友竟然全解锁版 v1.0.2
阿西美女室友竟然内置菜单版是游戏的破解版本,在该版本中为玩家
我是大东家正版 最新版v1.2.738
我是大东家正版是一款放置类模拟经营手游,玩家将回到古代成为家