Java 读写锁的应用 自定义的缓存系统

本文探讨了Hibernate中load方法的内部实现原理,通过User$Proxy代理对象展示了一级缓存的工作方式,并深入介绍了基于读写锁的简单缓存系统实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

熟悉Hibernate的童鞋  一定知晓Hibernate有一级缓存跟二级缓存 一级缓存是Hibernate默认开启的缓存 而二级缓存需要自己配置 此处只简单的讨论一个
Hibernate中load的内部实现原理
如果你要根据用户id获取用户的信息
User user = session.load(id,User.class);
此处返回的user类型是一个代理对象User$Proxy 而User$Proxy
User$Proxy extends User{
	//代理对象持有用户id
	private Integer id ;
	private User realUuser;
	
	public String getName(){
		//首先会查询缓存 如果缓存中有数据则直接返回
	    //如果缓存为空 则需要向数据查询 数据 
	    //如果从数据中也没有获取到数据 则抛出异常
	}	
}
故使用session.load方法时 如果没有查询到数据 会抛出异常 此处肯定有一些童鞋很好奇缓存机制是怎么实现的呢?
缓存系统会用读写锁 下面简单的介绍一个简单的缓存系统  实现原理
缓存肯定是多个线程并发访问的 故对效率要求极高 否则你的系统无法承受高并发访问..

大家了解一下读锁与写锁的一些关系
	1.读锁与读锁不互斥
       2.读锁与写锁互斥
       3.写锁与写锁互斥

读写锁的妙用 一个简单的缓存系统
/**
 * 
 * 一个简单的缓存系统
 */
class Cache{
//数据
private Object data;
//读写锁
ReadWriteLock rwl = new ReentrantReadWriteLock();
//获取数据 
public Object get(){
	//用户读取数据  开启读锁
	System.out.println(Thread.currentThread().getName()+"开始获取数据等待中.");
	rwl.readLock().lock();
	System.out.println(Thread.currentThread().getName()+"获取读锁 开始读取数据...");
	/**
	 *  当查询数据的过程中 出现异常 则不会执行下面的代码  而此时已经获取到读锁了
	 *  一旦发生异常  锁资源不能释放  故此处用try catch finally 保证资源得到释放
	 */
        try {
	    if ( data == null ) {
	    //由于无数据  需要向数据库查询 故要释放读锁
	    //开启写锁?因为要给data复制 故要开启写锁
	    System.out.println("数据为空:"+Thread.currentThread().getName()+":..");
	    rwl.readLock().unlock();
	    System.out.println(Thread.currentThread().getName()+" 释放读锁");
	    rwl.writeLock().lock();
	    //从数据中获取...
	    System.out.println(Thread.currentThread().getName()+" 获取写锁");
				 
	/**
	* 此处如果不判断数据是否为空 会出现什么情况呢?
	* 试想一下如果当三个线程同时访问该方法的时候.只有第一个线程可以获取写锁 
	* 其它线程处于等待...  当该线程写完数据之后 释放写锁
	* 第二个线程获得写锁  但是此时数据不再为空[第一个获取写锁的线程已经写入数据]
	* 如果此处不判断数据是否为空 第二个线程会再次查询数据并写入。
	* 如果是N个线程 同时访问该方法  则会查询N次数据并写入 效率可想而知!
	* 故为了提高效率 此处再次判断数据是否为空
	* 有兴趣的童鞋可以把此处的判断去掉  你看看会发现什么?
	*/
	if ( data == null ) {
		System.out.println(Thread.currentThread().getName()+"开始写入数据");
		//此处的数据应该是从DB中获取
		data = "data from db";
		System.out.println(Thread.currentThread().getName()+"数据写入完毕...");
	}
	//释放写锁  获取读锁
	/**
	* 如果是第二个线程获取到写锁之后  经过判断之后 数据不为空 
	* 则立即释放写锁  再次获取读锁
	* 至于先释放那个锁  再获取那个锁的顺序 
	*【如果此处是我自己 我可能会先释放写锁 
	* rwl.writeLock().unlock();
	* 在获取读锁
	* rwl.readLock().lock();】
	* 此处是模仿JDK文档中关于缓存释放和获取锁的顺序...
	*/
	rwl.readLock().lock();
	rwl.writeLock().unlock();
			
	}
   } catch (Exception e) {
		//异常处理
   } finally {
	rwl.readLock().unlock();
   }
   return data;
}
}

测试代码:
public static void main(String[] args) {
	final Cache cache = new Cache();
	for(int i = 0;i<3;i++){
		new Thread(){
			public void run() {
				Object data = cache.get();
				System.out.println(Thread.currentThread().getName()+"得到数据"+data.toString());
			};
		}.start();
	}
}



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值