读锁:共享锁:会发生死锁
死锁情况:有两个线程A和线程B,都要对一条数据进行读取并修改,而线程A要修改必须要等线程B读完之后进行,同样线程B要修改必须要等待线程A读完之后进行,此时会发生死锁。
写锁:独占锁:会发生死锁
死锁情况:有两个线程线程A和线程B,同时有两条数据,数据1和数据2,线程A要对数据1和数据2进行修改,线程B要对数据2和数据1进行修改,但A要等B对数据2修改完之后才能修改数据2,B要等A对数据1修改完之后才能修改数据1,此时发生互相等待,故会造成死锁
读写锁:一个资源可以被多个读线程访问,或者可以被一个写线程访问,但是不能同时存在读写线程,读写互斥,读读共享
缺点:1.造成锁饥饿,一直读,没有写操作
2.读时候,不能写,只有读完之后,才可以写,写操作可以读
/**
* @author
* @date 2022/12/28 21:17
* 读写锁演示
*/
//资源类
class MyCache{
//创建map集合
private volatile Map<String,Object> map= new HashMap<>();
//创建读写锁对象
private ReadWriteLock rwLock = new ReentrantReadWriteLock();
//写数据
public void put(String key,Object value) {
//添加写锁
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"正在写操作"+key);
//暂停一会
TimeUnit.MICROSECONDS.sleep(300);
//放数据
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写完了"+key);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
//释放锁
rwLock.writeLock().unlock();
}
}
//取数据
public Object get(String key){
//添加读锁
rwLock.readLock().lock();
Object result = null;
try {
System.out.println(Thread.currentThread().getName()+"正在进行读操作"+key);
TimeUnit.MICROSECONDS.sleep(300);
result = map.get(key);
System.out.println(Thread.currentThread().getName()+"取完了"+key);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放锁
rwLock.readLock().unlock();
}
return result;
}
}
public class ReadWriteDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
//创建线程放数据
for (int i = 1; i <= 5 ; i++) {
final int num = i;
new Thread(()->{
myCache.put(num+"",num+"");
},String.valueOf(i)).start();
}
//创建线程取数据
for (int i = 1; i <= 5 ; i++) {
final int num = i;
new Thread(()->{
myCache.get(num+"");
},String.valueOf(i)).start();
}
}
}
解释:从以上代码演示结果可以看到,写锁是独占的形式一个执行完之后另一个才可以执行,而读锁是共享的形式,多个线程可以同时进行。
锁降级:
/**
* @author
* @date 2022/12/29 21:41
*读写锁降级演示
*/
public class ReadWriteLockDemoteDemo {
public static void main(String[] args) {
//创建一个读写锁
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
//创建一个读锁
ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
//创建一个写锁
ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
//锁降级
writeLock.lock();
System.out.println("写操作");
readLock.lock();
System.out.println("读操作");
//释放写锁
writeLock.unlock();
//释放读锁
readLock.unlock();
}
}
解释:就是写时可读,读时不可以写;就像数据库的增删改与查询一样,增删改之前需要查找到相关数据才可以对相关数据进行操作,而查询时不可以对相关数据进行修改。