在旧的同步块中,我们使用相同的对象进行同步,还使用了 wait 和 notify 方法。因此他们都可以引用相同的锁。有道理。
因此,当我使用ReentrantLock类时,为什么不能同时使用相同的变量来调用 lock , unlock 以及 await 和信号?为什么我需要使其他Condition变量变?
这就是为什么我需要这样做:
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
void doSomething() {
lock.lock();
//some code
condition.await();
//some code
lock.unlock();
}
代替这个:(这种编码是否更逻辑)?
Lock lock = new ReentrantLock();
void doSomething() {
lock.lock();
//some code
lock.await();
//some code
lock.unlock();
}
编辑:来自文档:条件实例本质上绑定到锁。 为什么要这样设计?为什么不只有一个Lock类型的变量具有等待和信号方法呢?
答案 0 :(得分:4)
Lock
和Condition
的分隔允许您每个Condition
有多个Lock
,这由Condition
记录:
Condition
将Object
监视方法(wait
,notify
和notifyAll
)分解为不同的对象,从而具有多个每个对象的等待集 [强调添加] ,方法是将它们与任意Lock
实现组合使用。
还有Lock
:
[{
Lock
实现]允许更灵活的结构,可能具有完全不同的属性,并且可能支持多个关联的Condition
对象 [强调] >。
借助该功能,您可以执行以下操作:
import java.util.Objects;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Stack<E> {
private final Lock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
private final Condition notFull = lock.newCondition();
private final Object[] elements;
private int size;
public Stack(int capacity) {
elements = new Object[capacity];
}
public E pop() throws InterruptedException {
lock.lockInterruptibly();
try {
while (size == 0) {
notEmpty.await();
}
@SuppressWarnings("unchecked")
E element = (E) elements[--size];
elements[size] = null;
notFull.signal();
return element;
} finally {
lock.unlock();
}
}
public void push(E element) throws InterruptedException {
Objects.requireNonNull(element);
lock.lockInterruptibly();
try {
while (size == elements.length) {
notFull.await();
}
elements[size++] = element;
notEmpty.signal();
} finally {
lock.unlock();
}
}
}
这种方法有两个好处:
Condition
的线程才被发信号。signalAll()
,这意味着只唤醒了一个线程。这里是相同的Stack
类,但使用的是synchronized
:
import java.util.Objects;
public class Stack<E> {
private final Object lock = new Object();
private final Object[] elements;
private int size;
public Stack(int capacity) {
elements = new Object[capacity];
}
public E pop() throws InterruptedException {
synchronized (lock) {
while (size == 0) {
lock.wait();
}
@SuppressWarnings("unchecked")
E element = (E) elements[--size];
elements[size] = null;
lock.notifyAll();
return element;
}
}
public void push(E element) throws InterruptedException {
Objects.requireNonNull(element);
synchronized (lock) {
while (size == elements.length) {
lock.wait();
}
elements[size++] = element;
lock.notifyAll();
}
}
}
现在请注意,每个线程必须在相同的“条件”上等待,并且在发生任何事情时会通知每个等待的线程。您必须通知所有等待中的线程,因为您无法更好地控制要通知哪些线程。