ReadWriteLock
ReadWriteLock也是一个接口,提供了readLock和writeLock两种锁的操作机制,一个资源可以被多个线程同时读,或者被一个线程写,但是不能同时存在读和写线程。
读锁:共享锁 readLock
**写锁:**独占锁 writeLock
读写锁 : 一个资源可以被多个读的线程进行访问 ,或者可以被一个写的线程访问,
但是不能同时存在读和写进程 ,读写互斥,读读共享。
读的时候可以多个线程一起读
写的时候只能一个线程写
使用示例:
向map中添加和读取值
代码语言:javascript复制public class ReadWriteLock {
public static void main(String[] args) {
MyCache myCache = new MyCache();
//十个写线程
for (int i = 0; i < 10; i ) {
final int temp=i;
new Thread(() -> {
myCache.put(temp "",temp "");
}, String.valueOf(i)).start();
}
//十个读线程
for (int i = 0; i < 10; i ) {
final int temp=i;
new Thread(() -> {
myCache.get(temp "");
}, String.valueOf(i)).start();
}
}
}
/**
* 自定义缓存
*/
class MyMap {
private volatile Map<String, Object> map = new HashMap<>();
//存入值
public void put(String key, Object value) {
System.out.println(Thread.currentThread().getName() "写入" key);
map.put(key, value);
System.out.println(Thread.currentThread().getName() "写入完成");
}
//取值
public void get(String key) {
System.out.println(Thread.currentThread().getName() "读取" key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() "读取完成");
}
}
我们可以看到1写入跟写入完成之间插入了4线程 这是不对的
于是我们加入读写锁
加锁
代码语言:javascript复制 lock.writeLock().lock();
lock.readLock().lock();
解锁
代码语言:javascript复制 lock.writeLock().unlock();
lock.readLock().unlock();
代码语言:javascript复制class MyCacheLock {
private volatile Map<String, Object> map = new HashMap<>();
//读写锁 :更加细粒度的控制
private ReadWriteLock lock = new ReentrantReadWriteLock();
//存入值 写的时候只希望同时只有一个线程写
public void put(String key, Object value) {
//加写锁
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() "写入" key);
map.put(key, value);
System.out.println(Thread.currentThread().getName() "写入完成");
} catch (Exception e) {
} finally {
lock.writeLock().unlock();
}
}
//取值 读所有人都可以读
public void get(String key) {
//加读锁
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() "读取" key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() "读取完成");
} catch (Exception e) {
} finally {
lock.readLock().unlock();
}
}
}
读写锁的演变:
一、无锁
无锁状态多线程抢占资源 会出现问题
二、加锁
synchronized和reentrantLock
都是独占锁 每次只能一个线程来操作
读读 一个线程 只能一个人读
读写 一个线程
写写 一个线程
三、读写锁
ReentrantReadWriteLock
读读可以共享,提升性能 同时多人读
写写 一个线程
缺点:
1.造成锁的饥饿,可能一直读没有写的操作
2.写的时候,自己线程可以读,读的时候,哪个线程都不可以写
锁降级
锁降级:将写入锁降级为读锁 读锁不能升级为写锁
获取写锁—>获取读锁—>释放写锁—>释放读锁
示例:
代码语言:javascript复制public class Downgrade {
public static void main(String[] args) {
//可重入读写锁对象
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
//读锁
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
//写锁
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
//锁降级
//获取写锁
writeLock.lock();
System.out.println("飞飞");
//获取读锁
readLock.lock();
System.out.println("read读取");
//解锁
writeLock.unlock();
readLock.unlock();
}
}
但是我们不可以在读锁中获取写锁
示例:
代码语言:javascript复制public class Downgrade {
public static void main(String[] args) {
//可重入读写锁对象
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
//读锁
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
//写锁
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
//锁降级
//获取读锁
readLock.lock();
System.out.println("read读取");
//获取写锁
writeLock.lock();
System.out.println("飞飞");
//解锁
writeLock.unlock();
readLock.unlock();
}
}
不可以在读锁中写 不会停止