ReentrantReadWriteLock
读写锁
适合读多写少的场景。
读锁
ReentrantReadWriteLock.ReadLock
可以被多个线程同时持有, 所以并发能力很高。写锁
ReentrantReadWriteLock.WriteLock
是独占锁, 在一个线程持有写锁时候, 其他线程都不能在抢占, 包含抢占读锁都会阻塞。
读写锁的互斥原则如下:
- 读操作与读操作, 线程之间是可以共存的, 是相容的。
- 读操作与写操作、 线程之间不能共存的, 是互斥的、 当有写锁操作时候, 其他线程抢占读写锁都会等待阻塞。
- 写操作与写操作、线程之间不能共存的, 是互斥的、 当有写锁操作时候, 其他线程抢占读写锁都会等待阻塞。
例子:
// 可重入读写锁 (默认非公平)
private final static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 读写锁
private final static ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
private final static ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
// 共享临界资源
private volatile static Map<String, String> map = new HashMap<>();
@Test
public void applicationTest() throws Throwable {
map.put("1", "1-1");
// 并发20个线程同时去读
for (int i = 0; i < 20; i++) {
int j = i;
int finalJ = j;
executor.execute(() -> {
Thread thread = Thread.currentThread();
String threadName = thread.getName();
try {
// 大家都停止一会, 进行并发抢占锁
TimeUnit.SECONDS.sleep(3);
if (finalJ > 15) {
log.info(threadName + "线程暂停5秒啦");
// 15个线程后暂停5秒后在继续抢占读锁
TimeUnit.SECONDS.sleep(5);
}
readLock.lock();
log.info(threadName + "线程加读锁成功、读取到值" + map.toString());
} catch (InterruptedException e) {
log.error(threadName + "加锁失败啦");
} finally {
Tools.catchNoLogs(readLock::unlock);
}
});
}
// 8秒后进行写操作
TimeUnit.SECONDS.sleep(8);
writeLock.lock();
try {
map.put("name", "进行写入啦!");
log.info("主线程加写锁写入啦, 并写完, 不释放写锁8秒");
TimeUnit.SECONDS.sleep(8);
} catch (Exception e) {
e.printStackTrace();
} finally {
log.info("主线程写锁释放啦、 下面读锁可以继续抢占到读锁进行读取");
Tools.catchNoLogs(writeLock::unlock);
}
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}
结果:
从结果可以看出, 读锁可以多个线程同时抢占!
20:33:42.533 [[my-thread-2]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-2]线程加读锁成功、读取到值{1=1-1}
20:33:42.533 [[my-thread-15]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-15]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-6]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-6]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-3]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-3]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-1]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-1]线程加读锁成功、读取到值{1=1-1}
20:33:42.533 [[my-thread-11]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-11]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-9]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-9]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-13]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-13]线程加读锁成功、读取到值{1=1-1}
20:33:42.533 [[my-thread-7]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-7]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-10]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-10]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-8]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-8]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-4]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-4]线程加读锁成功、读取到值{1=1-1}
20:33:42.535 [[my-thread-12]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-12]线程加读锁成功、读取到值{1=1-1}
20:33:42.535 [[my-thread-5]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-5]线程加读锁成功、读取到值{1=1-1}
20:33:42.535 [[my-thread-16]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-16]线程加读锁成功、读取到值{1=1-1}
20:33:42.535 [[my-thread-14]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-14]线程加读锁成功、读取到值{1=1-1}
20:33:45.543 [[my-thread-12]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-12]线程暂停5秒啦
20:33:45.544 [[my-thread-8]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-8]线程暂停5秒啦
20:33:45.544 [[my-thread-6]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-6]线程暂停5秒啦
20:33:45.544 [[my-thread-4]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-4]线程暂停5秒啦
20:33:47.508 [main] INFO com.zhihao.demo.DemoApplicationTests - 主线程加写锁写入啦, 并写完, 不释放写锁8秒
20:33:55.508 [main] INFO com.zhihao.demo.DemoApplicationTests - 主线程写锁释放啦、 下面读锁可以继续抢占到读锁进行读取
20:33:55.510 [[my-thread-6]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-6]线程加读锁成功、读取到值{1=1-1, name=进行写入啦!}
20:33:55.510 [[my-thread-12]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-12]线程加读锁成功、读取到值{1=1-1, name=进行写入啦!}
20:33:55.510 [[my-thread-8]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-8]线程加读锁成功、读取到值{1=1-1, name=进行写入啦!}
20:33:55.510 [[my-thread-4]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-4]线程加读锁成功、读取到值{1=1-1, name=进行写入啦!}
1