ReentranReadWriteLock读写锁
一些锁的概念
共享锁(S锁)又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S 锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
排他锁(X锁)又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
-
读锁就是别人可以看,但是别人不能再修改
-
写锁就是别人既不能看,也不能修改
-
不论是写锁还是读锁都会造成死锁
当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式被称之为悲观并发控制
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量。
- 悲观锁上来就加锁
- 乐观锁只有再数据修改提交的时候才会检测,冲突就异常。
流程
public class RWLockDemo {
public static void main(String[] args) throws InterruptedException {
MyCatch myCatch = new MyCatch();
for (int i = 0; i < 5; i++) {
String key = String.valueOf(i);
new Thread(()->{
myCatch.put(key, UUID.randomUUID().toString().substring(0,8));
},key).start();
}
TimeUnit.SECONDS.sleep(2);
for (int i = 0; i < 5; i++) {
String key = String.valueOf(i);
new Thread(()->{
myCatch.get(key);
},key).start();
}
}
}
class MyCatch{
private volatile Map<String,String> map = new HashMap<>();
ReadWriteLock rwlock = new ReentrantReadWriteLock();
public void put(String key,String value){
rwlock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"\t准备写入数据");
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"\t写入数据完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
rwlock.writeLock().unlock();
}
}
public String get(String key){
rwlock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"\t准备读取数据");
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
String va = map.get(key);
System.out.println(Thread.currentThread().getName()+"\t读取数据完成");
return va;
} catch (Exception e) {
e.printStackTrace();
} finally {
rwlock.readLock().unlock();
}
return null;
}
}
与lock类似,无非是分类一下