示例模板
<span style="font-family: Arial, Helvetica, sans-serif;">package com.lei.lock;/*</span>
*@author leixingbang_sx *Mail:[email protected] *@create 2016/1/20 10:22 *desc 缓存例子 */ import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class CachedData { volatile boolean cacheValid;//是否被缓存 ReadWriteLock rwl=new ReentrantReadWriteLock();//可重入读写锁 *****位置M******* public void processCachedData()//处理缓存的数据 { Object data=null;//注意这里的data是线程私有的,而cacheMap是所有线程公用的 //所以只需要考虑cacheMap的读写锁的问题,而不需要考虑data rwl.readLock().lock();//读锁上锁 if(!this.cacheValid)//在缓存中并不存在 ********位置A******** { //1首先必须释放读锁,因为接下来需要从其他地方读取数据并写入。读写锁是互斥的 rwl.readLock().unlock(); //2写锁上锁 rwl.writeLock().lock();//位置获取写锁 ********位置B******** //3再次检测是否在缓存中存在数据,原因是可能存在一个线程在当前线程执行到位置A与位置B之间的时候 //获取了写锁,并写入数据将cachedValid状态改变 if(!this.cacheValid){ data=this.getData();//模拟从数据库或者文件系统等获取数据 this.cacheValid=true;//将状态更改为缓存系统中已经存在该数据 } //4 在释放写锁之前先进行降级 为了保证使用数据时,数据本身不被改变,需要读锁上锁,然后才释放写锁 // ********此处设计小知识点:当前线程自己的读锁和写锁并不冲突****** rwl.readLock().lock();// *****位置N******* //*********开始持有读锁*********************** rwl.writeLock().unlock();//释放写锁 } use(data); rwl.readLock().unlock();//释放读锁 在位置M、N处,读锁都进行了加锁所以这里需要将锁释放 } public Integer getData() { Integer a=new Random().nextInt(1000); return a; } public void use(Object data)//使用数据 { System.out.println(data); } public static void main(String[] args) { } }
实际例子:
package com.lei.lock;/* *@author leixingbang_sx *Mail:[email protected] *@create 2016/1/20 10:22 *desc 缓存例子 */ import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class CachedData { volatile boolean cacheValid;//是否被缓存 ReadWriteLock rwl=new ReentrantReadWriteLock();//可重入读写锁 *****位置M******* public void processCachedData()//处理缓存的数据 { Object data=null;//注意这里的data是线程私有的,而cacheMap是所有线程公用的 //所以只需要考虑cacheMap的读写锁的问题,而不需要考虑data rwl.readLock().lock();//读锁上锁 if(!this.cacheValid)//在缓存中并不存在 ********位置A******** { //1首先必须释放读锁,因为接下来需要从其他地方读取数据并写入。读写锁是互斥的 rwl.readLock().unlock(); //2写锁上锁 rwl.writeLock().lock();//位置获取写锁 ********位置B******** //3再次检测是否在缓存中存在数据,原因是可能存在一个线程在当前线程执行到位置A与位置B之间的时候 //获取了写锁,并写入数据将cachedValid状态改变 if(!this.cacheValid){ data=this.getData();//模拟从数据库或者文件系统等获取数据 this.cacheValid=true;//将状态更改为缓存系统中已经存在该数据 } //4 在释放写锁之前先进行降级 为了保证使用数据时,数据本身不被改变,需要读锁上锁,然后才释放写锁 // ********此处设计小知识点:当前线程自己的读锁和写锁并不冲突****** rwl.readLock().lock();// *****位置N******* //*********开始持有读锁*********************** rwl.writeLock().unlock();//释放写锁 } use(data); rwl.readLock().unlock();//释放读锁 在位置M、N处,读锁都进行了加锁所以这里需要将锁释放 } public Integer getData() { Integer a=new Random().nextInt(1000); return a; } public void use(Object data)//使用数据 { System.out.println(data); } public static void main(String[] args) { } }
什么是线程安全:在多线程访问的情况下,一个类总是能表现出正确的行为。
Lock提供比传统线程模型中的synchronized更加面向对象的方法,锁本身也是一个对象。两个线程的代码片段要实现同步互斥的效果,必须使用同一个Lock对象。锁要存放在要操作的资源的类的内部方法中,而不是线程代码。
读写锁的定义:分为读锁和写锁,多个线程的读锁之间互相不互斥(只读不修改),读锁和写锁互斥,写锁和写锁互斥(相互修改)。由jvm自己控制,只要上好对应的锁即可。Jdk1.5提供的新功能与特性。
重点:当自己挂上读锁的时候,仍然自己依然可以挂上写锁,但是其他线程不能挂上读锁,自己对自己是开放的。
如果希望提高性能,需要多个线程可以同时读,而又相互之间不冲突。
Hibernate复习
缓存的代理:
Useruser=session.load(id,User.class);返回的是一个User的代理对象,userProxy extends User
Eg: User$Proxy extends User{
Private Integer id=id;
User realUser=null;//保留了一个真正的User
getName(){
if(realUser==null)
{
realUser=seesion.get(id);
If(realUser==null)//对象为仍为空,则说明数据库中没有记录抛出异常
Throwexception
}else
{
Return realUser.getName();
}
Useruser=session.get(id,User.class);如果对象存在,则返回对象,不存在则返回null
面试题,设计一个缓存系统:
how to exploit reentrancy to perform lockdowngrading after updating a cache.
这是一个用来展示如何在更新缓存后利用可重入性执行锁定降级。
Exploit reentrancy 利用可重入性
Perform lock downgrading 执行锁定降级
Exception handling is elided for simplicity。
Exception handling 异常处理
Is elided 被忽略