为什么要用读写锁?它有什么优点?

开发 前端
在以上代码中,利用上述的工具类型,我们就可以轻松地提取 User 对象类型中函数类型和非函数类型的属性及相关的对象类型。

读写锁(Readers-Writer Lock)顾名思义是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,因为读操作本身是线程安全的,而写锁则是互斥锁,不允许多个线程同时获得写锁,并且写操作和读操作也是互斥的。总结来说,读写锁的特点是:读读不互斥、读写互斥、写写互斥。

1.读写锁使用

在 Java 语言中,读写锁是使用 ReentrantReadWriteLock 类来实现的,其中:

  • ReentrantReadWriteLock.ReadLock 表示读锁,它提供了 lock 方法进行加锁、unlock 方法进行解锁。
  • ReentrantReadWriteLock.WriteLock 表示写锁,它提供了 lock 方法进行加锁、unlock 方法进行解锁。

它的基础使用如下代码所示:

// 创建读写锁
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 获得读锁
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
// 获得写锁
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
// 读锁使用
readLock.lock();
try {
// 业务代码...
} finally {
readLock.unlock();
}
// 写锁使用
writeLock.lock();
try {
// 业务代码...
} finally {
writeLock.unlock();
}

1.1 读读不互斥

多个线程可以同时获取到读锁,称之为读读不互斥,如下代码所示:

// 创建读写锁
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 创建读锁
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
Thread t1 = new Thread(() -> {
readLock.lock();
try {
System.out.println("[t1]得到读锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t1]释放读锁.");
readLock.unlock();
}
});
t1.start();
Thread t2 = new Thread(() -> {
readLock.lock();
try {
System.out.println("[t2]得到读锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t2]释放读锁.");
readLock.unlock();
}
});
t2.start();

以上程序执行结果如下:

1.2 读写互斥

读锁和写锁同时使用是互斥的(也就是不能同时获得),这称之为读写互斥,如下代码所示:

// 创建读写锁
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 创建读锁
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
// 创建写锁
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
// 使用读锁
Thread t1 = new Thread(() -> {
readLock.lock();
try {
System.out.println("[t1]得到读锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t1]释放读锁.");
readLock.unlock();
}
});
t1.start();
// 使用写锁
Thread t2 = new Thread(() -> {
writeLock.lock();
try {
System.out.println("[t2]得到写锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t2]释放写锁.");
writeLock.unlock();
}
});
t2.start();

以上程序执行结果如下:

1.3 写写互斥

多个线程同时使用写锁也是互斥的,这称之为写写互斥,如下代码所示:

// 创建读写锁
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 创建写锁
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
Thread t1 = new Thread(() -> {
writeLock.lock();
try {
System.out.println("[t1]得到写锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t1]释放写锁.");
writeLock.unlock();
}
});
t1.start();

Thread t2 = new Thread(() -> {
writeLock.lock();
try {
System.out.println("[t2]得到写锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t2]释放写锁.");
writeLock.unlock();
}
});
t2.start();

以上程序执行结果如下:

2.优点分析

提高了程序执行性能:多个读锁可以同时执行,相比于普通锁在任何情况下都要排队执行来说,读写锁提高了程序的执行性能。

避免读到临时数据:读锁和写锁是互斥排队执行的,这样可以保证了读取操作不会读到写了一半的临时数据。

3.适用场景

读写锁适合多读少写的业务场景,此时读写锁的优势最大。

总结

读写锁是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,而写锁则是互斥锁。它的完整规则是:读读不互斥、读写互斥、写写互斥。它适用于多读的业务场景,使用它可以有效的提高程序的执行性能,也能避免读取到操作了一半的临时数据。

责任编辑:武晓燕 来源: Java面试真题解析
相关推荐

2022-07-13 07:06:47

HTTPSHTTP协议

2009-01-09 23:06:41

服务器SCSI硬盘PC

2020-04-07 16:12:56

Go编程语言开发

2023-12-21 21:39:44

2024-05-15 09:41:22

乐观锁编程

2021-12-13 01:40:29

ElasticSear倒排索引

2024-07-02 13:27:38

2021-05-11 06:57:15

HBaseBATJ公司

2024-01-02 17:28:12

芯片CPUAI计算

2015-07-01 10:25:07

Docker开源项目容器

2022-07-06 09:29:40

JMH性能测试

2016-01-12 16:58:31

C游戏

2023-09-22 10:05:32

2023-12-06 09:10:28

JWT微服务

2012-12-12 10:05:05

产品项目

2024-06-11 00:01:00

并发validate场景

2023-09-19 16:37:47

网络

2024-06-19 10:26:36

非阻塞IO客户端

2021-07-26 18:38:48

Bpmn流程

2021-02-09 20:51:13

D 语言脚本编程语言
点赞
收藏

51CTO技术栈公众号