📝个人主页🌹:个人主页
⏩收录专栏⏪:JAVA进阶
🌹🌹期待您的关注 🌹🌹,让我们共同进步!
ReentrantReadWriteLock可重入读写锁是读写锁的唯一实现。
多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行。但是,如果有一个线程想去写共享资源类,就不应该再有其他线程可以对该资源进行读或写。
小口诀: 读-读 能共存;读-写 不能共存;写-写 不能共存
有问题的例子
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache= new MyCache();
for (int i = 1; i < 6; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.put(tempInt+"", tempInt+"");
}, "Thread " + i).start();
}
for (int i = 1; i < 6; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.get(tempInt+"");
}, "Thread " + i).start();
}
}
}
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
public void put(String key, Object value) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t写入数据" + key);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t写入完成");
}
public void get(String key) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t读取数据");
Object result = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t读取完成" + result);
}
}
结果:
查看输出会发现,当一个线程在写的时候另外一个线程同时也在写,这种情况会引起重大的问题(比如数据库事务的ACID)。
使用读写锁
我们改下一下MyCache类,使用ReentrantReadWriteLock在写的时候加上写锁,在读的时候加上读锁(之所以加读锁是因为写的时候不能够进行读操作)当某个写线程获取到锁的时候,其他读/写线程均阻塞,当某个读线程获取到锁的时候,其他写线程均阻塞,读线程可并发访问资源类数据。
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key, Object value) {
readWriteLock.writeLock().lock(); // 加上写锁
try {
System.out.println(Thread.currentThread().getName() + "\t写入数据" + key);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t写入完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
public void get(String key) {
readWriteLock.readLock().lock(); // 加上读锁
try {
System.out.println(Thread.currentThread().getName() + "\t读取数据");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object result = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t读取完成" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
}