使用示例:
public void accessMutex() {
Lock lock = new ReentrantLock();
lock.lock();
try {
// access
} finally {
lock.unlock();
}
}使用示例:
public class ConditionExample {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean businessCondition = false;
public void waitCondition() throws InterruptedException {
lock.lock();
try {
while (!businessCondition) {
condition.await(); // 业务条件不满足,线程进入等待状态
}
} finally {
lock.unlock();
}
}
public void meetCondition() {
lock.lock();
try {
businessCondition = true;
condition.signal(); // 唤醒等待条件的线程
} finally {
lock.unlock();
}
}
}ReentrantLock内部类FairSync和NonFairSync继承了AbstractQueuedSynchronizer实现了公平锁和非公平锁,
比较\类型 | synchronized, wait/nofify | ReentrantLock, Condition |
|---|---|---|
加锁性能 | synchronized底层依赖了操作系统的Mutex,JVM对synchronized做了包括轻量锁在内的锁优化,但当锁多线程频繁竞争锁时,OS Mutex的使用涉及到内核态与用户态的频繁切换,性能上不如ReentrantLock | 使用CAS加锁,加锁主要逻辑在用户态中处理,频繁锁竞争下性能也较好 |
条件等待 | 在锁对象上调用wait/notify,可读性不好;无法区分不同业务条件 | 一个锁可对应多个业务条件,可读性更好;每个业务条件都单独对应一个等待队列,控制更精准 |
代码实现 | synchronized代码实现简洁明了,加锁逻辑简单、竞争较少的场景下优先使用synchronized | 锁竞争频繁、有Condition的使用时,优先使用ReentrantLock |
public class MyBlockingQueueV2<T> {
private Object[] data;
private int getIndex;
private int putIndex;
private int cnt;
private final Lock lock;
private final Condition notFull;
private final Condition notEmpty;
public MyBlockingQueueV2(int size) {
this.data = new Object[size];
this.lock = new ReentrantLock();
this.notFull = lock.newCondition();
this.notEmpty = lock.newCondition();
}
public void put(T item) throws InterruptedException {
lock.lock();
try {
while (cnt == data.length) { // 队列满,等待消费。线程唤醒后需重新检查条件是否满足
notFull.await();
}
data[putIndex] = item;
putIndex = nextIndex(putIndex);
cnt++;
notEmpty.signal(); // 唤醒等待的消费线程
} finally {
lock.unlock();
}
}
public T get() throws InterruptedException {
lock.lock();
try {
while (cnt == 0) { // 队列空,等待生产。线程唤醒后需重新检查条件是否满足
notEmpty.await();
}
Object item = data[getIndex];
getIndex = nextIndex(getIndex);
cnt--;
notFull.signal(); // 唤醒等待的生产线程
return (T) item;
} finally {
lock.unlock();
}
}
private int nextIndex(int curIndex) {
return (curIndex + 1) % data.length;
}
}详细完整逻辑可以参考JDK的ArrayBlockingQueue.
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。