读写锁
概述
事实上,咱们之前学习的锁其实都有一点小小的问题,那就是其锁的粒度太大了,像是Synchronized 和 ReentrantLock 都是独占锁,即在同一时间只要一个线程获取到锁。而许多情况下,咱们的许多操作并不是互斥的,完全可以支撑并行履行,并不需要加锁来进行约束,十分的不灵活,那么有没有一个能够让咱们更加自在的挑选加锁的办法呢?
ReentrantReadWriteLock
读写锁,望文生义是一把锁分为两部分:读锁
和写锁
,其中读锁允许多个线程一起取得,是一个共享锁,由于读操作本身是线程安全的;而写锁则是排他锁,不允许多个线程一起取得写锁,并且写操作和读操作也是互斥的。
主要处理:对共享资源有读和写的操作,且写操作没有读操作那么频频的场景。
特点
- 公正性:读写锁支撑非公正和公正的锁获取办法,非公正锁的吞吐量优于公正锁的吞吐量,默许结构的是非公正锁
- 可重入:在线程获取读锁之后能够再次获取读锁,可是不能获取写锁,而线程在获取写锁之后能够再次获取写锁,一起也能获取读锁
- 锁降级:线程获取写锁之后获取读锁,再开释写锁,这样完成了写锁变为读锁,也叫锁降级
其更适合读多写少的场景。读锁可以被多个线程一起持有, 所以并发才干很高;而写锁是独占锁, 在一个线程持有写锁时候, 其他线程都不能在抢占, 包括抢占读锁都会阻塞
使用
常用办法
办法 | 描绘 |
---|---|
public ReentrantReadWriteLock() | 默许结构办法,非公正锁 |
public ReentrantReadWriteLock(boolean fair) | true 为公正锁 |
public ReentrantReadWriteLock.ReadLock readLock() | 回来读锁 |
public ReentrantReadWriteLock.WriteLock writeLock() | 回来写锁 |
public void lock() | 加锁 |
public void unlock() | 解锁 |
public boolean tryLock() | 测验获取锁 |
现在有个餐厅,其生意非常好,客人特别多,于是其要求来的客人必须先抢票才干进来用餐。于是有很多人想来用餐的就要去抢票,一起还有许多吃瓜大众看还有多少票剩余。咱们来完成这个案例
public class Restaurant {
private volatile int num = 6;
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
public void grabTickets() {
boolean isGet = false;
//获取写锁
rwLock.writeLock().lock();
//锁降级,获取读锁
rwLock.readLock().lock();
try {
if (num > 0) {
--num;
isGet = true;
} else {
System.out.println(Thread.currentThread().getName() + "没票了");
}
} finally {
//开释写锁
rwLock.writeLock().unlock();
}
try {
if (isGet) {
System.out.println(Thread.currentThread().getName() + "抢到了票,现在还剩余的票数为:" + num);
}
} finally {
//开释读锁
rwLock.readLock().unlock();
}
}
public void getNum() {
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "检查了现在的票数:" + num);
} finally {
rwLock.readLock().unlock();
}
}
}
咱们这里在抢票时,为了其他线程可以更快地检查当前票数,咱们选用锁降级。
然后是咱们履行的代码
public class RestaurantTest {
public static void main(String[] args) {
Restaurant restaurant = new Restaurant();
for (int i = 0; i < 10; ++i) {
new Thread(restaurant::grabTickets, "食客" + (i + 1)).start();
new Thread(restaurant::getNum, "吃瓜大众" + (i + 1)).start();
}
}
}
来看一下履行结果
用户1抢到了票,现在还剩余的票数为:5
吃瓜大众1检查了现在的票数:5
吃瓜大众2检查了现在的票数:5
用户2抢到了票,现在还剩余的票数为:4
用户3抢到了票,现在还剩余的票数为:3
吃瓜大众3检查了现在的票数:3
用户4抢到了票,现在还剩余的票数为:2
吃瓜大众6检查了现在的票数:2
吃瓜大众4检查了现在的票数:2
吃瓜大众5检查了现在的票数:2
用户7抢到了票,现在还剩余的票数为:1
用户6抢到了票,现在还剩余的票数为:0
用户5没票了
吃瓜大众9检查了现在的票数:0
吃瓜大众7检查了现在的票数:0
用户9没票了
用户8没票了
吃瓜大众8检查了现在的票数:0
用户10没票了
吃瓜大众10检查了现在的票数:0
进程已结束,退出代码0
这就是这篇文章的内容了,欢迎大家的讨论,如有讹夺,也请指出,谢谢~