【问题标题】:What's a monitor in Java?Java 中的监视器是什么?
【发布时间】:2011-03-22 16:42:33
【问题描述】:

Java 并发编程中的监视器是指什么?

当我读到“每个对象都关联了一个监视器”时,这是什么意思?

它是一个特殊的物体吗?

【问题讨论】:

  • +1 这让我了解了监视器是如何在 JVM 级别实现的。学到了新东西
  • @naikus 我希望与您分享详细信息 :)

标签: java multithreading concurrency monitor


【解决方案1】:

监视器是控制对对象的并发访问的机制。

这允许你做:

线程 1:

public void a()
{
    synchronized(someObject) {
        // do something (1)
    }
}

线程 2:

public void b()
{
    synchronized(someObject) {
        // do something else (2)
    }
}

这可以防止线程 1 和 2 同时访问受监视(同步)部分。一个将启动,监视器将阻止另一个在第一个完成之前访问该区域。

这不是一个特殊的对象。它的同步机制位于类层次结构根:java.lang.Object

还有waitnotify 方法也将使用对象的监视器在不同线程之间进行通信。

【讨论】:

  • 那么我们可以说当我们创建一个同步方法时,我们在该对象的方法上定义了一个锁(监视器)吗?
  • 呃,不完全是。每个对象都自动有一个与之关联的监视器(互斥体),不管其他什么。当您声明同步的方法时,您声明运行时必须在该方法开始执行之前获得对象监视器上的锁(并且必须在控制返回到调用代码之前释放锁)。
  • 还有@Pablo - 没有方法监视器这样的东西;监视器只存在于对象,这将是大多数方法的封闭实例,或对应的Class 静态方法的对象。如果您已经有一个同步的 method1() 并且您声明 method2() 同步,则不会创建新的监视器,实际上调用任一方法(在同一个对象上)将尝试锁定同一个监视器。这通常会吸引新人。
  • @Andrzej:所以,每个对象都有一个与之关联的监视器。然后我可以有很多同步方法。在任何时候调用该方法后,线程调用它都会获得执行同步操作的监视器。
  • 只需要澄清这一点...用于在线程1中调用同步块的对象可以在另一个线程(线程2)中再次使用以调用正常方法(非同步)在同一时间?
【解决方案2】:

监视器是一个同时拥有等待集的实体。在 Java 中,任何Object 都可以用作监视器。

有关监视器如何在 Java 中工作的详细说明,我建议阅读 Concurrent Programming in JavaMonitor Mechanics 部分(前面的链接显示 Google 书籍中的预览,并且该部分可供阅读)。

【讨论】:

  • 正如你所说的“监视器是一个实体......”,这是否意味着监视器是一个拥有/跟踪锁和等待集的内部对象/状态?如果不是,您能否在此处详细说明实体?基本上当我们java文档说Wakes up all threads that are waiting on this object's monitor.关于notifyall()时,我得到的是对象正在维护(在内部实体/对象的帮助下)所有线程都在等待锁定,那个内部实体/对象被称为监视器?跨度>
  • 最有用的答案。谢谢@JRL。
  • 对我来说,它说:“此页面没有可用的预览。”
【解决方案3】:
  1. 监视器是一种不限于 Java 语言的概念/机制;
  2. “在并发编程中,监视器是一个对象或模块,旨在被多个线程安全使用”;
  3. 每个读者都知道,Java 中的每个对象都是 java.lang.Object 的子类。 Java 人员以这样一种方式制作 java.lang.Object,使其具有使 Java 程序员能够将任何对象用作监视器的特性和特性。例如,每个对象都有一个等待队列、一个重入队列以及使其成为监视器的等待和通知方法;
  4. 了解监视器here

【讨论】:

    【解决方案4】:

    在并发编程中,我们需要关注两件事

    1. 互斥

    当一个进程/线程正在执行其临界区时,不允许其他进程执行其临界区。 (每个进程都有一个称为“关键部分”的代码段,其中访问共享数据。)

    1. 同步

    当线程试图通过协同工作来实现一个共同目标时,这些线程需要它们之间的合作。当他们专注于一个共同的目标时,他们需要同步。

    监控器用于实现互斥和同步。


    如何轻松理解Monitor?

    不要把这个临界区和临界区混为一谈,因为这里提到的临界区是对象级的,而不是线程级的。 共享数据被认为是临界区。

    每个对象及其类都与一个监视器相关联。需要防止并发访问的对象的实例变量包括与对象相关联的监视器的关键区域和需要防止并发访问的类的实例变量/静态变量包括在关键区域中与类关联的监视器。

    • 这个关键区域有一个锁保护,这个锁确保互斥。

    • Wait 集还与用于提供线程间协调的监视器相关联。

    • 条目集用于保存已经请求锁但尚未获得锁的线程。

    如何在 Monitor 上实现互斥?


    每个对象都与一个监视器相关联,并且此监视器有一个,每个线程都可以使用此锁定或解锁对象strong> 当它访问共享变量时。明确地说,这意味着一次只有一个线程可以在监视器上持有。任何其他试图锁定该 lock 的线程都会被阻止,直到它们能够获得 lock。当一个新线程尝试获取锁并且如果已经有一个线程拥有锁,那么该线程将等待条目集以获取锁。当获得锁的线程完成其临界区时,它将释放锁。所以下一个线程将获取锁,但下一个线程取自条目集,将由 JVM 根据 FIFO 等标准确定。

    在这里,我们实现的是互斥,因为我们为对象提供了对线程的独占访问权限,并且不允许任何其他线程进入它们的临界区。

    使用监视器实现互斥的示例 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.
          }
    
    

    如何通过 Monitor 实现协调/同步?

    使用与监视器相关联的等待集和“等待并通知”或“信号并继续”机制来实现同步。当一个线程时,同步很重要需要一些数据处于特定状态,另一个线程负责将数据放入该状态,例如生产者/消费者问题

    当一个线程调用对象的 wait() 方法时,该线程挂起并添加到等待集以等待,直到其他线程调用同一对象上的 notify() 或 notifyAll()。

    notify() 方法用于唤醒处于特定对象的监视器的等待集中的线程。通知等待线程的方法有两种。

    • notify() --> 对于等待设置的所有线程,notify() 方法通知它们中的任何一个任意唤醒。选择唤醒哪个线程是不确定的,取决于 JVM。
    • 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/

    【讨论】:

      【解决方案5】:

      【讨论】:

        【解决方案6】:

        Java 语言和运行时系统通过使用监视器来支持线程同步。
        监视器与特定数据项(条件变量)相关联,并用作对该数据的锁定。当一个线程持有某个数据项的监视器时,其他线程被锁定并且无法检查或修改数据。

        【讨论】:

          【解决方案7】:

          Monitor 是一种同步构造,它允许线程同时具有互斥和等待(阻塞)某个条件变为真的能力。

          监视器还有一种机制,用于向其他线程发出信号,告知其条件已满足。它是一个同时拥有锁和等待集的实体。在 Java 中,任何 Object 都可以用作监视器。

          在 Java 虚拟机中,每个对象和类在逻辑上都与一个监视器相关联。为了实现监视器的互斥功能,每个对象和类都关联了一个锁(有时称为互斥锁)。这在操作系统术语中称为信号量,互斥量是二进制信号量。

          For more information check the link

          【讨论】:

            【解决方案8】:

            http://journals.ecs.soton.ac.uk/java/tutorial/java/threads/monitors.html

            monitor 与对象或数据成员相关联,当数据成员或对象进入同步块(临界区)时获取,退出时释放。

            【讨论】:

              猜你喜欢
              • 2015-10-16
              • 2010-09-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-09-11
              • 1970-01-01
              • 2010-10-09
              • 1970-01-01
              相关资源
              最近更新 更多