Lock读写锁技术的妙用
1.面试题1:三个线程读,三个线程写同一个数据
public class ReadWriteLockTest {
public static void main(String[] args) {
final Queue3 q3 = new Queue3();
for(int i=0;i<3;i++){
//3个读线程
new Thread(new Runnable() {
@Override
public void run() {
while(true){
q3.get();
}
}
}).start();
//3个写线程
new Thread(new Runnable() {
@Override
public void run() {
q3.set(new Random().nextInt(10000));
}
}).start();
}
}
}
class Queue3{
private Object data = null; //共享数据,只能有一个线程能写该数据,但可以有多个线程同时读
ReadWriteLock lock = new ReentrantReadWriteLock();
public void get(){
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName()+" be ready to read data!");
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName()+" have read data: "+data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.readLock().unlock();
}
}
public void set(Object data){
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName()+" be ready to write data!");
Thread.sleep((long)(Math.random()*1000));
this.data = data;
System.out.println(Thread.currentThread().getName()+" hava write data: "+data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.writeLock().unlock();
}
}
}
2.
Hibernate中两者的区别
① User user = session.load(id,User.class);
② User user = session.get(id,User.class);
其中②直接从数据库查询,如果查询为空,user为null
其中①在查询时,无论数据路有没有都会得到:User$Proxy 代理类,是一个缓存的User
如果实际的realUser为空则查询数据库,如果从数据库查询出的为空,抛异常,如果不为空
直接返回realUser.getName()
User$Proxy extends User{ private Integer id = id; User realUser = null;
getName(){
if(realUser == null){
realUser = session.get(id);
if(realUser == null)
throw exception //抛异常
}
return realUser.getName();
} }
3.javaAPI 上的一段代码:
1 Sample usages. Here is a code sketch showing how to exploit reentrancy to perform lock downgrading after updating a cache (exception handling is elided for simplicity):
2
3 class CachedData {
4 Object data;
5 volatile boolean cacheValid;
6 ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
7
8 void processCachedData() { //处理数据
9 rwl.readLock().lock(); //多个线程并发读,不冲突,只需要上一个读锁
10 if (!cacheValid) { //检查缓存中有没有数据 if中的代码好比第一次获取数据
11 // Must release read lock before acquiring write lock
12 rwl.readLock().unlock(); //如果一个线程发现没有数据,释放读锁,获取写锁
13 rwl.writeLock().lock();
14 // Recheck state because another thread might have acquired
15 // write lock and changed state before we did.
16 if (!cacheValid) {
17 data = ... //实际的写数据逻辑
18 cacheValid = true; //缓存标志改为true,表示有缓存数据了
19 }
20 // Downgrade by acquiring read lock before releasing write lock
21 rwl.readLock().lock();
22 rwl.writeLock().unlock(); // Unlock write, still hold read
23 }
24
25 use(data); //使用数据
26 rwl.readLock().unlock();
27 }
28 }
4.面试题:设计一个缓存系统
1 public class CacheDemo { 2 3 private Map<String,Object> cache = new HashMap<>(); 4 public static void main(String[] args) { 5 6 } 7 8 private ReadWriteLock rwl = new ReentrantReadWriteLock(); 9 public Object getData(String key){ 10 rwl.readLock().lock(); //获取读锁 11 Object value = null; 12 try { 13 value = cache.get(key); 14 if(value == null){ 15 rwl.readLock().unlock(); 16 rwl.writeLock().lock(); 17 try { 18 if(value == null){ 19 value = "aaa"; //实际是去数据库查询 20 } 21 } finally{ 22 rwl.writeLock().unlock(); 23 } 24 rwl.readLock().lock(); 25 } 26 } catch (Exception e) { 27 e.printStackTrace(); 28 }finally{ 29 rwl.readLock().unlock(); //释放读锁 30 } 31 return value; 32 } 33 34 }