在 Java 中并发编程中,什么是监视器?
当我读到“每个对象都与一个监视器相关联”时,这是什么意思?
是特殊物品吗?
监视器是控制对对象的并发访问的机制。
你可以这样做:
线程1:
public void a() { synchronized(someObject) { // do something (1) } }
线程2:
public void b() { synchronized(someObject) { // do something else (2) } }
这可以防止线程1和线程2同时访问被监视的(同步的)部分。其中一个将启动,监视器将阻止另一个在第一个完成之前访问该区域。
它不是一个特殊的对象,它是放置在类层次结构根目录下的同步机制: java.lang.Object。
java.lang.Object
还有 wait和 notify方法,它们也将使用对象的监视器在不同的线程之间进行通信。
wait
notify
Http://java.sun.com/docs/books/jvms/second_edition/html/concepts.doc.html#33308
一个 机械装置来控制对对象的访问
监视器是同时拥有 锁定和 等一下的实体。在 Java 中,任何 Object都可以作为监视器。
Object
要了解 Java 中监视器如何工作的详细说明,我建议阅读 Java 中的并发编程的 < em > 监控机械师 部分(前面的链接显示了 Google 图书中的预览,该部分可供阅读)。
Http://journals.ecs.soton.ac.uk/java/tutorial/java/threads/monitors.html
Monitor 与对象或数据成员关联,当数据成员或对象被输入时获取它是同步块(关键部分) ,当退出时释放。
Monitor 是一种同步结构,允许线程同时具有互斥锁和等待(阻塞)的能力,以使某个条件成为真实。
监视器还有一种机制,用于通知其他线程它们的条件已经得到满足。它是一个同时拥有锁和等待集的实体。在 Java 中,任何对象都可以作为监视器。
在 Java 虚拟机中,每个对象和类都在逻辑上与一个监视器相关联。为了实现监视器的互斥锁功能,每个对象和类都有一个锁(有时称为互斥锁)。这在操作系统术语中称为信号量,互斥量是一个二进制信号量。
有关详细信息,请查看链接
在并发编程中,我们需要关注两件事
当一个进程/线程正在执行其关键部分时,不允许其他进程执行其关键部分。(每个进程都有一个称为“关键部分”的代码段,在其中访问共享数据。)
当线程试图通过协同工作来实现一个共同目标时,这些线程需要它们之间的协作。当他们专注于一个共同的目标时,他们需要同步。
监视器用来实现互斥锁和同步。
不要混淆这个关键区域和关键部分,因为这里提到的关键区域是在对象级别,而不是在线程级别。共享数据被认为是一个关键领域。
每个对象及其类都与一个监视器相关联。需要防止并发访问的对象的实例变量包括与对象关联的监视器的关键区域,以及需要防止并发访问的类的类/静态变量的实例变量,这些实例变量包括与类关联的监视器的关键区域。
这个关键区域被一把锁保护着,这把锁确保了互斥锁。
等待集还与用于在线程之间提供协调的监视器相关联。
一个条目集用于保存已经为锁请求的线程,而这些线程尚未获得锁。
每个对象都与一个监视器相关联,并且这个监视器有一个 锁定,当每个线程访问共享变量时,它可以使用这个 锁定锁定或解锁这个对象。显然,这意味着一次只有一个线程可以在监视器上保存 锁定。试图锁定该 锁定的任何其他线程都将被阻塞,直到它们能够获得 锁定。当一个新线程试图获取锁时,如果已经有一个线程拥有锁,那么该线程将等待条目集来获取锁。当获取锁的线程完成其关键部分时,它将释放锁。因此,下一个线程将获得锁,但是下一个线程将从条目集中获取,并且将由 JVM 基于某些条件(如 FIFO)来确定。
在这里,我们实现的是互斥锁,因为我们给对象一个线程的独占访问权,而且我们不允许任何其他线程进入它们的关键部分。
使用 monitor 实现互斥的 Java 代码示例
class Counter { private int count = 0; public void synchronized Increment() { int n = count; count = n+1; } //Here synchronized is used to indicate those things should be done sequentially. }
同步是使用与监视器和“等待和通知”或“信号和继续”机制相关联的等待集来实现的。当一个线程需要一些数据处于某个特定的状态,而另一个线程负责让数据进入该状态时,同步非常重要,例如,生产者/消费者问题
当一个线程对对象调用 wait ()方法时,该线程挂起并添加到等待集中,直到其他线程调用同一对象上的 notifyAll ()。
通知()方法用于唤醒位于特定对象的监视器的等待集中的线程。有两种通知等待线程的方式。
在生产者消费者问题中使用监视器实现同步的 Java 代码示例
class Buffer { private char [] buffer; private int count = 0, in = 0, out = 0; Buffer(int size) { buffer = new char[size]; } public synchronized void Put(char c) { while(count == buffer.length) { try { wait(); } catch (InterruptedException e) { } finally { } } System.out.println("Producing " + c + " ..."); buffer[in] = c; in = (in + 1) % buffer.length; count++; notify(); } public synchronized char Get() { while (count == 0) { try { wait(); } catch (InterruptedException e) { } finally { } } char c = buffer[out]; out = (out + 1) % buffer.length; count--; System.out.println("Consuming " + c + " ..."); notify(); return c; } }
请参阅以下连结 Http://www.csc.villanova.edu/~mdamian/threads/javamonitors.html#:~:text=java%20associates%20a%20monitor%20with,the%20monitor%20for%20that%20object Https://howtodoinjava.com/java/multi-threading/how-to-use-locks-in-java-java-util-concurrent-locks-lock-tutorial-and-example/