Version: Next

读写锁

ReadWriteLock接口

  • 唯一实现类:ReentrantReadWriteLock
  • readLock()writeLock()
  • 维护了一对Lock,一个用于读、另一个用于写
  • 读取时,允许多个线程读 (共享锁
  • 写入时,只允许一个线程写 (独占锁)(互斥锁

例 自定义缓存

/***
* 自定义缓存
*/
class MyCache {
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 Object get(String key) {
System.out.println(Thread.currentThread().getName() + "读取 -> " + key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "读取完毕-> ");
return o;
}
}
public static void main(String[] args) {
MyCache myCache = new MyCache();
//写入操作
for (int i = 0; i < 5; i++) {
final int tempI = i;
new Thread(() -> {
myCache.put(tempI + "", tempI);
}, "Thread" + i).start();
}
//读取操作
for (int i = 0; i < 5; i++) {
final int tempI = i;
new Thread(() -> {
myCache.get(tempI + "");
}, "Thread").start();
}
}
  • 运行结果
Thread0写入 -> 0
Thread3写入 -> 3
Thread2写入 -> 2
Thread1写入 -> 1
Thread1写入完毕->
Thread2写入完毕->
Thread3写入完毕->
Thread0写入完毕->
Thread4写入 -> 4
Thread4写入完毕->
Thread读取 -> 0
Thread读取完毕->
Thread读取 -> 1
Thread读取完毕->
Thread读取 -> 2
Thread读取完毕->
Thread读取 -> 3
Thread读取 -> 4
Thread读取完毕->
Thread读取完毕->

这行结果有问题,在进行一次写入时,另一次写入又进来了

给自定义缓存加读写锁

/***
* 带锁自定义缓存
*/
class MyCache2 {
private volatile Map<String, Object> map = new HashMap<>();
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
// 存,写入,只允许一个线程
public void put(String key, Object value) {
//加写锁
reentrantReadWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "写入 -> " + key);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写入完毕-> ");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放写锁
reentrantReadWriteLock.writeLock().unlock();
}
}
// 取,读取,允许多个线程
public Object get(String key) {
Object o = null;
reentrantReadWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "读取 -> " + key);
o = map.get(key);
System.out.println(Thread.currentThread().getName() + "读取完毕-> ");
} catch (Exception e) {
e.printStackTrace();
} finally {
reentrantReadWriteLock.readLock().unlock();
}
return o;
}
}
public static void main(String[] args) {
MyCache2 myCache = new MyCache2();
//写入操作
for (int i = 0; i < 5; i++) {
final int tempI = i;
new Thread(() -> {
myCache.put(tempI + "", tempI);
}, "Thread" + i).start();
}
//读取操作
for (int i = 0; i < 5; i++) {
final int tempI = i;
new Thread(() -> {
myCache.get(tempI + "");
}, "Thread").start();
}
}
Thread0写入 -> 0
Thread0写入完毕->
Thread1写入 -> 1
Thread1写入完毕->
Thread2写入 -> 2
Thread2写入完毕->
Thread3写入 -> 3
Thread3写入完毕->
Thread4写入 -> 4
Thread4写入完毕->
Thread读取 -> 0
Thread读取完毕->
Thread读取 -> 1
Thread读取 -> 3
Thread读取 -> 2
Thread读取完毕->
Thread读取 -> 4
Thread读取完毕->
Thread读取完毕->
Thread读取完毕->
  • 可以看到,在写入时,线程严格排队写入;在读取时多个线程同时读
  • 读、写互斥