来自Programming Language Pragmatics, by Scott
仅使用同步方法的Java对象(无锁或 synchronized语句非常类似于 Mesa监视器 每个监视器有一个条件变量的限制(事实上 具有同步语句的对象有时被称为 用Java监控。)
为什么仅使用同步方法的Java对象非常类似于Mesa监视器,其中每个监视器有一个条件变量的限制?
“仅使用同步方法的Java对象”中是否存在条件变量是否正确?那么它怎么能像一个带有一个条件变量的监视器呢?
出于同样的原因, Java中的同步语句开始 在循环中等待类似于重新测试的CCR 条件已明确。因为通知也是明确的, Java实现不需要重新评估条件(或唤醒 在批判的每个出口处明确地执行此操作的线程 部分 - 仅发生通知的那些。
为什么Java中的同步语句开始 在一个循环中等待类似于CCR(条件关键区域),其中条件的重新测试已经明确?
“因为通知也是显式的,所以Java实现不需要在关键部分的每个出口处重新评估条件(或唤醒明确执行此操作的线程) - 仅发生通知的那些”?< / p>
感谢。
答案 0 :(得分:0)
所有这一切都在说,在Java中,内部锁具有融入其中的条件。将此与ReentrantLock进行对比,您可以使用相同的锁明确地具有单独的条件。
如果您有单独的条件,那么您可以发出给定条件的信号,并且只知道该条件的等待集中的线程将接收它。如果您没有单独的条件对象,则在收到通知后您必须检查该条件是否适用于您。
这样的一个例子是固定大小的阻塞队列。如果你看一下ArrayBlockingQueue,它是用ReentrantLock实现的,这样就可以使用单独的条件对象。如果这是使用Queue对象上的内部锁实现的,则必须使用notifyAll来唤醒等待线程,然后必须测试它们从等待中醒来的状态,以确定它是否与它们相关。
这是使用内部锁写入的阻塞队列。如果使用了notify,那么调度程序将唤醒单个线程并且(因为线程可能正在等待放置或等待采取),它可能是也可能不是通知与之相关的线程。为确保通知不会丢失,所有等待的线程都会收到通知:
public class Queue<T>{
private final int maxSize;
private List<T> list = new ArrayList<>();
public Queue(int maxSize) {
this.maxSize = maxSize;
}
public synchronized T take() throws InterruptedException {
while (list.size() == 0) {
wait();
}
notifyAll();
return list.remove(0)(
}
public synchronized void put(T entry) throws InterruptedException {
while (list.size() == maxSize) {
wait();
}
list.add(entry);
notifyAll();
}
}