读写锁的特性
读读是共享的。读写,写写是互斥的。
1.读读互斥例子
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReentrantReadWriteLockDemo {
private int i = 0;
private int j = 0;
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
Lock readLock = lock.readLock();
Lock writeLock = lock.writeLock();
public void out(){
readLock.lock();
System.out.println(Thread.currentThread().getName()+",(i="+i+"j="+j+")");
readLock.unlock();
}
public void increase(){
writeLock.lock();
try {
i++;
Thread.sleep(500l);
j++;
}catch (InterruptedException e){
e.printStackTrace();
}finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
ReentrantReadWriteLockDemo reentrantReadWriteLockDemo = new ReentrantReadWriteLockDemo();
new Thread(()->{
reentrantReadWriteLockDemo.increase();
},"写线程1").start();
new Thread(()->{
reentrantReadWriteLockDemo.increase();
},"写线程2").start();
}
}
在increase()方法打断点,进行多线程debug,当写线程1获取到写锁时,写线程2尝试去获取锁,显示无法获取锁,进入等待状态,由此说明,写写是互斥的。
2.读写互斥,我们将main方法如下修改一下,再debug。
public static void main(String[] args) {
ReentrantReadWriteLockDemo reentrantReadWriteLockDemo = new ReentrantReadWriteLockDemo();
new Thread(()->{
reentrantReadWriteLockDemo.increase();
},"写线程1").start();
new Thread(()->{
reentrantReadWriteLockDemo.out();
},"读线程2").start();
}
在increase()和out()方法上打上断点,进行多线程debug,如下写线程1和读线程2正常启动
当写线程1获得锁时,读线程2尝试去获得锁,读线程2拿不到锁,进入等待状态(反之先让读线程2先获取锁时,再让写线程1尝试获得锁的也是一样的,写线程会获取失败进入等待状态,这里就不一一展示了),说明读写也是互斥的。
3.读读不互斥,我们将mian方法再改一下
public static void main(String[] args) {
ReentrantReadWriteLockDemo reentrantReadWriteLockDemo = new ReentrantReadWriteLockDemo();
new Thread(()->{
reentrantReadWriteLockDemo.out();
},"读线程1").start();
new Thread(()->{
reentrantReadWriteLockDemo.out();
},"读线程2").start();
}
debug结果如下,在读线程1获得读锁时,读线程2仍然可以获取到读锁,说明读读是不互斥的
4.锁降级
写锁程序获得写入锁后可以获得读取锁,然后释放写入锁,这样就从写入锁变成读写锁,从而实现读写锁的降级。
注意
锁降级之后,血锁并不会直接降成读锁,不会随着读锁的释放而释放,因此需要显示地释放写锁
简单例子
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LockDegrade {
public static void main(String[] args) {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
Lock readLock = lock.readLock();
Lock writeLock = lock.writeLock();
writeLock.lock();
readLock.lock();
writeLock.unlock();
readLock.unlock();
System.out.println("运行结束");
}
}
运行结果如下,主线程获得写锁之后可以获得读锁,并且写锁释放后,后面的释放读锁代码也正常运行,说明读锁在写锁释放后仍然能用。
锁降级的应用
数据比较敏感,需要在对数据修改后获取到数据 修改后的值,做其他操作。