具有同步方法和同步语句的对象如何分别类似于监视器和条件关键区域?

时间:2017-10-14 22:32:51

标签: java multithreading concurrency synchronization programming-languages

来自Programming Language Pragmatics, by Scott

  

仅使用同步方法的Java对象(无锁或   synchronized语句非常类似于 Mesa监视器   每个监视器有一个条件变量的限制(事实上   具有同步语句的对象有时被称为   用Java监控。)

为什么仅使用同步方法的Java对象非常类似于Mesa监视器,其中每个监视器有一个条件变量的限制?

“仅使用同步方法的Java对象”中是否存在条件变量是否正确?那么它怎么能像一个带有一个条件变量的监视器呢?

  

出于同样的原因, Java中的同步语句开始   在循环中等待类似于重新测试的CCR   条件已明确。因为通知也是明确的,   Java实现不需要重新评估条件(或唤醒   在批判的每个出口处明确地执行此操作的线程   部分 - 仅发生通知的那些。

为什么Java中的同步语句开始  在一个循环中等待类似于CCR(条件关键区域),其中条件的重新测试已经明确?

“因为通知也是显式的,所以Java实现不需要在关键部分的每个出口处重新评估条件(或唤醒明确执行此操作的线程) - 仅发生通知的那些”?< / p>

感谢。

1 个答案:

答案 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();
    }
}