Java中,monitor和lock有什么区别

In Java, what is the difference between a monitor and a lock

使用synchronized关键字的方法,使用javap命令查看字节码,发现使用了monitor,如果实现synchronized的时候可以调用monitor,我的理解是这样吧?如果不正确请更正。他们之间是什么关系?锁和监视器是什么关系?

this document中,您可以找到问题的答案:

Synchronization. The Java programming language provides multiple mechanisms for communicating between threads. The most basic of these methods is synchronization, which is implemented using monitors. Each object in Java is associated with a monitor, which a thread can lock or unlock.

来自Locks and Synchronization的官方文档:

  • Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.")
  • Every object has an intrinsic lock associated with it. By convention, a thread has to acquire the object's monitor lock before accessing them, and then release the monitor lock when it's done with them. A thread is said to own the lock between the time it has acquired the lock and released the lock. As long as a thread owns a monitor lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.
  • When a thread releases the lock, a happens-before relationship is established between that action and any subsequent acquisition of the same lock.

所以monitor和lock并不能相提并论,它们是相辅相成的。 Java 中的每个对象都与一个监视器相关联,线程可以 lockunlock.

锁是一种数据,它在逻辑上是堆内存上 object 的 header 的一部分。 JVM 中的每个 object 都有这个锁(或互斥锁),任何程序都可以使用它来协调 multi-threaded 对 object 的访问。如果任何线程想要访问那个 object 的实例变量;然后线程必须“拥有”object 的锁(在锁内存区域设置一些标志)。所有其他尝试访问 object 变量的线程必须等到拥有线程释放 object 的锁(取消设置标志)。

一旦一个线程拥有一个锁,它可以多次再次请求同一个锁,但是在它被其他线程使用之前必须释放相同次数的锁。例如,如果一个线程三次请求锁,那么该线程将继续拥有该锁,直到它三次“释放”它。

请注意,锁是在线程明确请求时获取的。在 Java 中,这是通过 synchronized 关键字或 wait 和 notify 完成的。

监视器

Monitor 是一种同步构造,它允许线程同时具有互斥(使用锁)和协作,即让线程等待特定条件为真(使用wait-set)的能力。

换句话说,除了实现锁的数据外,每个 Java object 在逻辑上都与实现 wait-set 的数据相关联。锁帮助线程在共享数据上独立工作而不会相互干扰,而 wait-sets 帮助线程相互合作以实现共同目标,例如所有等待的线程都将移至此 wait-set,一旦锁被释放,所有线程都会收到通知。 wait-set 借助锁(互斥锁)的额外帮助构建监视器。

有关更多说明,请参阅 -

UNDERSTANDING THREADS, MONITORS AND LOCKS

Difference between lock and monitor – Java Concurrency

文档 https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html 可能不是找出 Lock 和 Monitor 之间区别的好地方,尤其是它提到的术语:intrinsic lockmonitor lock 和简单的 monitor,这似乎表明 monitor 和 lock 是可以互换的。

这不是真的。

Monitor 是用于multi-thread 同步的结构。它由一个锁和几个条件变量组成。条件变量是一个队列,当给定条件不符合要求时,线程可以将它们放入其中。当条件为真时,其他某个线程可以唤醒这些线程。条件变量是一种帮助线程相互协作的方式。

在简单的同步情况下,我们只使用监视器提供的锁,就像这个例子:

class SimpleCase {
  int counter;

  synchronized inc() int {
    return counter++;
  }
} 

inc()的线程不需要协作,只需要加锁使线程互斥,从而使counter线程安全。

而在更复杂的情况下,不仅需要互斥(mutex),还需要配合

例如,有界consumer/producer问题:多个消费者和生产者消费消息并将消息发送到队列。需要配合,因为消息队列有一个最大大小,当队列满时,不能再发送消息,当队列为空时,不能再消费消息。

下面是显示生产者的代码:

package monitor;

public class Producer {
    BoundedQueue queue;

    public Producer(BoundedQueue queue) {
        this.queue = queue;
    }

    public void send(int msg) throws InterruptedException {
        synchronized (queue) {
            // wait till there is room to produce
            while (queue.isFull()) {
                queue.wait();
            }

            // business logic here
            queue.add(msg);
            System.out.println("sent:" + msg + ", from:" + Thread.currentThread().getName());

            // before exit, call notify() to wake up waiting threads
            queue.notifyAll();
        }// implicit release the lock when exiting the synchronized block
    }
}

代码中,BoundedQueue作为监听器,除了互斥,生产者和消费者还需要配合:当队列满了,生产者需要wait(),当队列满了,生产者需要wait()有空位,生产者需要通知从等待中唤醒,生产者发送数据到队列后,还需要调用notifyAll()以防有消费者在等待对于队列不为空的条件。

这里waitnotify的能力是Monitor提供的,让线程协同

希望这可以帮助您了解监控和锁定之间的区别。

参考:

A​​ monitor 是互斥、等待外部条件为真的能力以及将该事件通知其他线程的能力的组合。 条件和通知部分本质上是 cooperation

A​​ lock提供互斥。这意味着它可以防止多个线程同时访问相同的数据。

注意监视器使用互斥。所以用锁来实现监视器。