廖雪峰Java11多线程编程-3高级concurrent包-2ReadWriteLock
1.ReentrantLock的限制
ReentrantLock保证了只有一个线程可以执行临界区代码。
临界区代码:任何时候只有1个线程可以执行的代码块。
临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待,有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用,例如:semaphore。只能被单一线程访问的设备,例如:打印机。
public void inc(){
lock.lock();
try{
value += 1;
}finally{
lock.unlock();
}
}
public int get(){
lock.lock();
try(){
return value;
}finally{
lock.unlock();
}
}
但有时候,这种保护有些过头:
- 因为我们发现任何时刻只允许1个线程修改,对inc()进行加锁是必须的。
- 但是get()方法只读取数据,不修改数据。它应该允许多个线程同时调用。
我们期望:允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待。
2. ReadWriteLock
使用ReadWriteLock可以解决:
- 只允许一个线程写入(其他线程既不能写入,也不能读取)
- 没有写入时,多个线程允许同时读(提高性能)
- 实现
class Counter{
final ReadWriteLock lock = new ReentrantReadWriteLock();
//分别获得readLock和writeLock
final Lock rlock = lock.readLock();
final Lock wlock = lock.writeLock();
private int value = 0;
public void inc(){
wlock.lock();
try{
value += 1;
}finally {
wlock.unlock();
}
}
public int get(){
rlock.lock();
try{
return this.value;
}finally {
rlock.unlock();
}
}
}
3.示例
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class Count{
private ReadWriteLock lock = new ReentrantReadWriteLock();
private Lock rlock = lock.readLock();
private Lock wlock = lock.writeLock();
private int value = 0;
public void add(int m){
wlock.lock();
try{
value += m;
}finally {
wlock.unlock();
}
}
public void dec(int m){
wlock.lock();
try{
value -= m;
}finally {
wlock.unlock();
}
}
public int get(){
rlock.lock();
try{
return value;
}finally {
rlock.unlock();
}
}
}
public class Main{
final static int LOOP = 100;
public static void main(String[] args) throws Exception{
Count count = new Count();
Thread t1 = new Thread(){
public void run(){
for(int i=0;i<LOOP;i++){
count.add(1);
}
}
};
Thread t2 = new Thread(){
public void run(){
for(int i=0;i<LOOP;i++){
count.dec(1);
}
}
};
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(count.get());
}
}

ReadWriteLock适用条件:
- 同一个实例,有大量线程读取,仅有少数线程修改。
- 例如论坛帖子,回复视为写入,不频繁操作;浏览器看作读取,非常频繁。这种情况下,就可以适用ReadWriteLock
4. 总结:
使用ReadWriteLock可以提高读取效率:
- ReadWriteLock只允许一个线程写入。
- ReadWriteLock允许多个线程同时读取。
- ReadWriteLock适合读多写少的场景。
廖雪峰Java11多线程编程-3高级concurrent包-2ReadWriteLock的更多相关文章
- 廖雪峰Java11多线程编程-3高级concurrent包-5Atomic
Atomic java.util.concurrent.atomic提供了一组原子类型操作: 如AtomicInteger提供了 int addAndGet(int delta) int increm ...
- 廖雪峰Java11多线程编程-3高级concurrent包-4Concurrent集合
Concurrent 用ReentrantLock+Condition实现Blocking Queue. Blocking Queue:当一个线程调用getTask()时,该方法内部可能让给线程进入等 ...
- 廖雪峰Java11多线程编程-3高级concurrent包-1ReentrantLock
线程同步: 是因为多线程读写竞争资源需要同步 Java语言提供了synchronized/wait/notify来实现同步 编写多线程同步很困难 所以Java提供了java.util.concurre ...
- 廖雪峰Java11多线程编程-3高级concurrent包-6ExecutorService
Java语言内置多线程支持: 创建线程需要操作系统资源(线程资源,栈空间) 频繁创建和销毁线程需要消耗大量时间 如果可以复用一个线程 线程池: 线程池维护若干个线程,处于等待状态 如果有新任务,就分配 ...
- 廖雪峰Java11多线程编程-3高级concurrent包-9Fork_Join
线程池可以高效执行大量小任务: Fork/Join线程池可以执行一种特殊的任务: 把一个大任务拆成多个小任务并行执行 Fork/Join是在JDK 1.7引入的 示例:计算一个大数组的和 Fork/J ...
- 廖雪峰Java11多线程编程-3高级concurrent包-8CompletableFuture
使用Future可以获得异步执行结果 Future<String> future = executor.submit(task); String result = future.get() ...
- 廖雪峰Java11多线程编程-3高级concurrent包-7Future
JDK提供了ExecutorService接口表示线程池,可以通过submit提交一个任务. ExecutorService executor = Executors.newFixedThreadPo ...
- 廖雪峰Java11多线程编程-3高级concurrent包-3Condition
Condition实现等待和唤醒线程 java.util.locks.ReentrantLock用于替代synchronized加锁 synchronized可以使用wait和notify实现在条件不 ...
- 廖雪峰Java11多线程编程-2线程同步-3死锁
1.线程锁可以嵌套 在多线程编程中,要执行synchronized块: 必须首先获得指定对象的锁 Java的线程锁是可重入的锁.对同一个对象,同一个线程,可以多次获取他的锁,即同一把锁可以嵌套.如以下 ...
随机推荐
- 数据结构C++版-队列
一.概念 分类: 二.补充说明 1.<面向对象的队列设计>课程问答: 首先要明确数据结构和数据存储结构的概念. 数据结构是指数据对象之间的逻辑关系,例如二叉树,队列,栈等,而数据存储结构是 ...
- JavaScript笔记 - Object对象特性的应用
可以依据js对象中key是永远不会重复的原则,来模拟Map类型以及去除数组重复项. 1.模拟Map类型 (1)构造Map对象 function Map(){ //private var obj = { ...
- SQLServer 安装失败可能的原因
问题:安装的时候显示参数指定的目录无效 解决:你的安装盘使用了文件/文件夹压缩功能,去掉压缩属性即可! 建议不要轻易使用储存盘的压缩功能
- Linux环境下Jmeter 报错:Unable to get local host IP address
主要是没有在host中配置本机ip hostname查看本机名 [root@test task]# hostname test [root@test task]# 打开 [root@test task ...
- 正版STlink的使用注意
https://blog.csdn.net/xinghuanmeiying/article/details/78026561
- 在CentOS 7上安装常用的YUM源
参考地址:https://blog.csdn.net/u010048823/article/details/51298183 以epel源为例子,来讲解如何添加额外的YUM源. Extra Packa ...
- spark函数sortByKey实现二次排序
最近在项目中遇到二次排序的需求,和平常开发spark的application一样,开始查看API,编码,调试,验证结果.由于之前对spark的API使用过,知道API中的sortByKey()可以自定 ...
- mysql双主热备
先搭建mysql主从模式,主从请参考mysql 主从笔记 然后在在配置文件里添加如下配置 1 log_slave_updates= #双主热备的关键参数.默认情况下从节点从主节点中同步过来的修改事件是 ...
- 校园商铺-2项目设计和框架搭建-5配置maven
/src/main/java 存放业务的Java代码 /src/main/resources 存储项目所用到的资源文件,如各种Spring,batis,日志的配置文件 /src/test/java 单 ...
- 专访阿里云MVP黄胜蓝:90 后 CTO花了6年,改变了你日常生活里的这件事
[黄胜蓝:现任武汉极意网络科技有限公司CTO.高中时期NOIP一等奖保送至武汉大学,大学期间曾指导团队获得世界数学建模大赛金奖,同时负责武汉大学学生校园门户网站的运维工作.于2013年加入武汉极意网络 ...