【发布时间】:2018-09-11 15:11:32
【问题描述】:
使用synchronized关键字方法,使用javap命令查看字节码,发现使用了monitor,如果实现synchronized的时候可以调用monitor,是我的理解吧?如果您不这样做,请更正。他们之间是什么关系?锁和监视器是什么关系?
【问题讨论】:
标签: java locking synchronized
使用synchronized关键字方法,使用javap命令查看字节码,发现使用了monitor,如果实现synchronized的时候可以调用monitor,是我的理解吧?如果您不这样做,请更正。他们之间是什么关系?锁和监视器是什么关系?
【问题讨论】:
标签: java locking synchronized
在this document,您可以找到问题的答案:
同步。 Java 编程语言提供了多种 线程之间的通信机制。其中最基本的 方法是同步,使用监视器实现。每个 Java 中的对象与一个监视器相关联,该监视器是一个线程 可以锁定或解锁。
【讨论】:
来自Locks and Synchronization的官方文档:
- 同步是围绕称为内在锁或监控锁的内部实体构建的。 (API 规范通常将此实体简称为“监视器”。)
- 每个对象都有一个与之关联的内在锁。按照惯例,线程必须获取对象的监视器锁 在访问它们之前,然后释放 监控锁 和他们一起完成。据说一个线程在它之间拥有锁 已获得锁并释放锁。只要一个线程拥有 一个监视器锁,没有其他线程可以获取相同的锁。另一个 线程在尝试获取锁时会阻塞。
- 当线程释放锁时,会在该操作与任何后续获取 同一个锁。
因此,监视器和锁不能比较差异,而是相互补充。 Java 中的每个对象都与一个监视器相关联,线程可以锁定或解锁。
【讨论】:
锁
锁是一种数据,它在逻辑上是堆内存上对象头的一部分。 JVM 中的每个对象都有这个锁(或互斥锁),任何程序都可以使用它来协调对对象的多线程访问。如果任何线程想要访问该对象的实例变量;然后线程必须“拥有”对象的锁(在锁内存区域设置一些标志)。所有其他试图访问对象变量的线程都必须等到拥有线程释放对象的锁(取消设置标志)。
一旦一个线程拥有一个锁,它可以多次再次请求同一个锁,但必须释放相同次数的锁,然后才能将其提供给其他线程。例如,如果一个线程请求锁 3 次,则该线程将继续拥有该锁,直到它“释放”它 3 次。
请注意,锁是由线程在明确请求时获取的。在 Java 中,这是通过 synchronized 关键字或等待和通知来完成的。
监视器
Monitor 是一种同步结构,它允许线程同时具有互斥(使用锁)和协作,即能够让线程等待某个条件为真(使用等待集)。
换句话说,与实现锁的数据一起,每个 Java 对象在逻辑上都与实现等待集的数据相关联。锁帮助线程在共享数据上独立工作而不会相互干扰,而等待集帮助线程相互合作以实现共同目标,例如所有等待的线程都将被移动到这个等待集,一旦锁被释放,所有的线程都会得到通知。此等待集有助于在锁定(互斥)的额外帮助下构建监视器。
有关更多说明,请参阅 -
【讨论】:
文档 https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html 可能不是一个很好的地方来找出 Lock 和 Monitor 之间的区别,尤其是它提到的术语:intrinsic lock、monitor lock 和简单的 monitor,这似乎表明 monitor 和锁是可以互换的。
这不是真的。
Monitor 是一种用于多线程同步的结构。它由一个锁和几个条件变量组成。条件变量是一个队列,当给定条件不符合要求时,线程可以将它们放入队列中。当条件为真时,其他一些线程可以唤醒这些线程。条件变量是一种帮助线程相互协作的方式。
在简单的同步情况下,我们只使用监视器提供的锁,比如这个例子:
class SimpleCase {
int counter;
synchronized inc() int {
return counter++;
}
}
做inc()的线程不需要合作,只需要锁就可以使线程互斥,从而使counter线程安全。
而在更复杂的情况下,不仅需要互斥(mutex),还需要合作。
例如,有界消费者/生产者问题:多个消费者和生产者消费并将消息发送到队列。需要合作,因为消息队列有一个最大大小,当队列满时,不能再发送消息,当队列为空时,不能再消费消息。
下面是生产者的代码:
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(),队列有可用槽时生产者需要通知从等待中唤醒,生产者向队列发送数据后,还需要调用notifyAll(),以防有消费者在等待队列不为空的情况。
这里,wait 和 notify 的能力由 Monitor 提供,以使线程协作。
希望这可以帮助您了解 Monitor 和 Lock 之间的区别。
参考:
【讨论】:
monitor 是互斥、等待外部条件为真的能力以及通知其他线程该事件的能力的组合。 条件和通知片本质上是cooperation
lock 提供互斥。这意味着它可以防止多个线程同时访问相同的数据。
注意监视器使用互斥。因此,锁是用来实现监视器的。
【讨论】: