示例模板
<span style="font-family: Arial, Helvetica, sans-serif;">package com.lei.lock;/*</span>
*@author leixingbang_sx
*Mail:leixingbang_sx@qiyi.com
*@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:leixingbang_sx@qiyi.com
*@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 被忽略