java基于ConcurrentHashMap设计细粒度实现代码

细粒度锁:

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 ConcurrentHashMap<String,Object> userMap=new ConcurrentHashMap<String,Object>();
	//用户金额map
	private static ConcurrentHashMap<String,Integer> moneyMap=new ConcurrentHashMap<String,Integer>();
	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的线程没有同步

总结

以上就是本文关于java基于ConcurrentHashMap设计细粒度实现代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以参阅:权限控制之粗粒度与细粒度概念及实现简单介绍、javaweb设计中filter粗粒度权限控制代码示例等,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

(0)

相关推荐

  • 几种JAVA细粒度锁的实现方式

    最近在工作上碰见了一些高并发的场景需要加锁来保证业务逻辑的正确性,并且要求加锁后性能不能受到太大的影响.初步的想法是通过数据的时间戳,id等关键字来加锁,从而保证不同类型数据处理的并发性.而java自身api提供的锁粒度太大,很难同时满足这些需求,于是自己动手写了几个简单的扩展... 1. 分段锁 借鉴concurrentHashMap的分段思想,先生成一定数量的锁,具体使用的时候再根据key来返回对应的lock.这是几个实现里最简单,性能最高,也是最终被采用的锁策略,代码如下: /** * 分

  • java基于ConcurrentHashMap设计细粒度实现代码

    细粒度锁: java中的几种锁:synchronized,ReentrantLock,ReentrantReadWriteLock已基本可以满足编程需求,但其粒度都太大,同一时刻只有一个线程能进入同步块,这对于某些高并发的场景并不适用.比如银行客户a向b转账,c向d转账,假如这两个线程并发,代码其实不需要同步.但是同时有线程3,e向b转账,那么对b而言必须加入同步.这时需要考虑锁的粒度问题,即细粒度锁. 网上搜寻了一些关于java细粒度锁的介绍文章,大部分是提供思路,比如乐观锁,String.i

  • java基于swing实现的连连看代码

    本文实例讲述了java基于swing实现连连看代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: package llkan; import javax.swing.*; import java.awt.*; import java.awt.event.*; /**  * 连连看游戏  * @author Administrator  *2014年10月17日  */ public class MainGame implements ActionListener {     

  • Java基于redis实现分布式锁代码实例

    为什么会有这个需求: 例如一个简单用户的操作,一个线程去修改用户状态,首先在在内存中读出用户的状态,然后在内存中进行修改,然后在存到数据库中.在单线程中,这是没有问题的.但是在多线程中由于读取,修改,写入是三个操作,不是原子操作(同时成功或失败),因此在多线程中会存在数据的安全性问题. 这个问题的话,就可以用分布式锁在限制程序的并发执行. 实现思路: 就是进来一个先占位,当别的线程进来操作的时候,发现有人占位了,就会放弃或者稍后再试. 占位的实现: 在redis中的setnx命令来实现,redi

  • Java实现计算器设计

    本文实例为大家分享了Java实现计算器设计的具体代码,供大家参考,具体内容如下 需求分析 目的是实现一个基于Java的可以求解带括号加减乘除表达式的带界面的计算器. 需要知道的Java技术:Java Swing(Java图形界面设计).Java集合(栈).lambda表达式.Java基础等. 设计思路 1.实现一个Java计算器界面类 2.实现一个Java计算带括号加减乘除表达式的类 3.实现主函数调用 设计实现 Java计算器项目结构: Calculator类为计算器界面设计.Calculat

  • java基于swing实现的五子棋游戏代码

    本文实例讲述了java基于swing实现的五子棋游戏代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Main extends JFrame implements ActionListener{         private static final long serialVersionUID = 1L;      

  • Java基于Swing实现的打猎射击游戏代码

    本文实例讲述了Java基于Swing实现的打猎射击游戏代码.分享给大家供大家参考. 具体实现代码如下: 复制代码 代码如下: package Game; import java.awt.Graphics; import java.awt.Image; import javax.swing.JPanel; public class BackgroundPanel extends JPanel {         private static final long serialVersionUID

  • Java基于swing实现的弹球游戏代码

    本文实例讲述了Java基于swing实现的弹球游戏代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: package Game; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Random;

  • java使用RandomAccessFile类基于指针读写文件实例代码

    java API中提供了一个基于指针操作实现对文件随机访问操作的类,该类就是RandomAccessFile类,该类不同于其他很多基于流方式读写文件的类.它直接继承自Object. public class RandomAccessFile extends Objectimplements DataOutput, DataInput, Closeable{...} 1.使用该类时可以指定对要操作文件的读写模式. 第一种模式是只读模式,第二种模式是读写模式.在创建该类实例时指定. @Test pu

  • java基于poi导出excel透视表代码实例

    这篇文章主要介绍了java基于poi导出excel透视表代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 从前,我是一个前端程序猿,怀着对打通任(前)督(后)二(开)脉(发)的梦想转了后端,自学两礼拜java+spring全家桶,直接上项目实战.最近接到一需求:将业务数据导出一张透视表. 需求开发完成已近有一段时间了,甲方的大爷大妈,爷爷奶奶们也都用的很开心,我也很开心,于是就心想咱学了也不能白学,所以写下这篇随笔. 先看下用easypo

  • 基于java web获取网页访问次数代码实例

    这篇文章主要介绍了基于java web获取网页访问次数代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 ServletContext context = request.getServletContext(); /** * 从ServletContext中获取计数器对象 */ Integer count = (Integer) context.getAttribute("counter"); /** * 如果为空,则在Servl

随机推荐