读写锁ReentrantReadWriteLock简介
ReentrantReadWriteLock是ReadWriteLock接口的实现,ReentrantReadWriteLock中有两个静态内部类:ReadLock读锁和WriteLock写锁,这两个锁实现了Lock接口,ReentrantReadWriteLock支持可重入,同步功能依赖自定义同步器(AbstractQueuedSynchronizer)实现,读写状态就是其同步器的同步状态。同步状态由一个整型变量表示,因为这个变量需要表示多个线程的读和写的状态,因此读写锁在实现上将该变量的高16位表示读,低16位表示写。
写锁的获取和释放
写锁WriteLock是支持重进入的排他锁。如果当前线程已经获取了写锁,则增加写状态。如果当前线程在获取读锁时,读锁已经被获取或者该线程不是已获取写锁的线程,则当前线程进入等待状态。读写锁确保写锁的操作对读锁可见。写锁释放每次减少写状态,当前写状态为0时表示写锁已背释放。
读锁的获取与释放
读锁ReadLock是支持重进入的共享锁,它能够被多个线程同时获取,在没有其他写线程访问(写状态为0)时,读锁总是能够被成功地获取,而所做的也只是增加读状态(线程安全)。如果当前线程已经获取了读锁,则增加读状态。如果当前线程在获取读锁时,写锁已经被获取,则进入等待状态。
public class LockTest {
public static void main(String[] args) {
final Quen quen = new Quen();
for(int i=0;i<30;i++){
new Thread(){
@Override
public void run() {
quen.get();
}
}.start();
new Thread(){
@Override
public void run() {
quen.put(new Random().nextInt(1000));
}
}.start();
}
}
}
class Quen{
/*共享数据*/
private Object data = null;
/*读写锁*/
private ReadWriteLock lock = new ReentrantReadWriteLock();
public void get(){
/*读锁*/
lock.readLock().lock();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"------"+data);
lock.readLock().unlock();
}
public void put(Integer i){
/*写锁*/
lock.writeLock().lock();
try {
Thread.sleep(1000);
this.data = i;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("写"+Thread.currentThread().getName()+"----"+data);
lock.writeLock().unlock();
}
}
多线程读不互斥,写互斥
模拟了一个cache类
class CacheTest{
/*模拟缓存*/
private volatile Map cache = new HashMap();
/*读写锁 解决多线程问题 使用javaee5 的lock解决*/
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public Object get(String key){
/*当o为null的时候有一个线程加了写锁 那么后面再今天的线程 全部阻塞在这里 读锁和写锁是互斥的*/
rwl.readLock().lock();
Object o = null;
try {
o = cache.get(key);
if(null == o){
/*释放读锁 */
rwl.readLock().unlock();
/*加上写锁 最开始并发进来的 线程在此争抢写锁,阻塞 写锁与写锁互斥*/
rwl.writeLock().lock();
try {
/*避免最开始并发线程的再去读数据库*/
if(null == o){
o = "数据库取数据";
cache.put(key,o);
}
}finally {
/*释放写锁*/
rwl.writeLock().unlock();
}
/*加上读锁*/
rwl.readLock().lock();
}
}finally {
rwl.readLock().unlock();
}
return o;
}
}