当前位置: 首页 > 知识库问答 >
问题:

Java不同方法同步同一对象上的块

司空奕
2023-03-14

我试图理解java中同步块的概念。根据我读过的文档,我明白如果我们获取一个锁(使用实例变量的同步块),那么我们就不能在该类中的同一对象上获取同步锁。但是当我尝试实际使用以下片段时,我发现我的理解出了问题。

即我能够同时以两种不同的方法获取锁(同一实例变量上的同步块)。当线程启动时,它将转到run方法并无限期地等待,并且不会从同步块中出来。同时,如果我使用相同的线程调用stop方法,它会进入同步块并执行通知语句。我在Java文档中搜索,但找不到任何。

这是代码段:

public class MyClass extends Thread
{
    private Object lock = new Object(); 
    public void run()
    {
      synchronized(lock)
      {
          lock.wait()
      }
      //other code
    }
    public void stop()
    {
      synchronized(lock)
      {
          lock.notify()
      }
      //other code
    } 
}

下面是我如何管理MyClass线程的代码片段:

public class MyClassAdmin 
{
    MyClass _myclass;
    public MyClassAdmin()
    {
        _myclass=new MyClass();
        _myclass.start();
    }
    public void stop()
    {
    _myclass.stop();
    }
    public static void main(String args[])
    {
    MyClassAdmin _myclassAdmin=new MyClassAdmin();
    _myclassAdmin.stop();
    }
}

根据我的理解,当线程启动时,它将获取“lock”对象上的锁(MyClass的run方法中的同步块)。当我调用stop方法时,它应该无限期地等待,直到run方法从同步块中出来(在这种情况下永远不会发生)。但当我执行时,调用stop方法获取了“lock”对象上的锁,并通知该对象,从而导致线程关闭。

共有2个答案

严兴旺
2023-03-14

这是多线程的,它可能会永远等待,也可能不会。在您的情况下,您很幸运_myclassAdmin。停止();在MyClass开始执行并执行wait()后执行;

在将方法stop()名称更改为stop1()后,我运行了程序,它永远在等待。

要获得一致的行为,请在main中的两个方法调用之间放置1秒的睡眠时间,例如:

MyClassAdmin _myclassAdmin=new MyClassAdmin();
Thread.sleep(1)
_myclassAdmin.stop();

现在,执行总是会停止。

此外,当一个线程调用wait()时,它会释放与之关联的监视器,因此任何其他线程都可以获取该锁并发出notify() / notifyAll()来唤醒等待的线程。这是意料之中

康弘义
2023-03-14

您的两个方法都使用相同的锁。如果您的MyClass线程碰巧在主线程可以调用Stop方法之前开始等待,您的Stop方法仍然可以继续,因为等待线程会释放锁。一旦线程进入等待方法,它会在进入Hibernate状态之前释放锁,并且在退出等待方法之前不会重新获取锁。

这是对象#wait的相关API文档,第二段介绍了我在上面描述的wait如何释放锁。请注意它说您必须在循环中调用此方法的部分,否则会出现顺序依赖性错误,当通知到达主线程时,该错误会导致等待线程挂起,然后其他线程才能开始等待。

公共最终无效wait__t()抛出中断异常

导致当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法。换言之,此方法的行为就像它只是执行调用等待(0)。

当前线程必须拥有这个对象的监视器。该线程释放该监视器的所有权,并一直等待,直到另一个线程通过调用notify方法或notifyAll方法通知等待该对象的监视器的线程被唤醒。然后,线程等待,直到它可以重新获得监视器的所有权,并继续执行。

与单参数版本一样,中断和虚假唤醒是可能的,这种方法应该始终在循环中使用:

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait();
     ... // Perform action appropriate to condition
 }  

此方法只能由作为此对象监视器所有者的线程调用。有关线程成为监视器所有者的方式的描述,请参见notify方法。

理解这是一个玩具示例,但子类化线程和重写线程方法令人困惑。使用Runnable而不是Thread的原因之一是,错误地重写Thread方法不会导致问题。

 类似资料:
  • 假设我们有两个类A、B和各自类的同步方法methodA、methodB。如果我们从synchronizedmethodA调用synchronized methodB,那么当methodB仍在执行时,线程是否仍对ObjectA保持锁定?

  • 我在阅读oracle的多线程官方教程时,遇到了这个例子(假设< code>c1和< code>c2从未一起使用): 据说通过使用锁1 然而,我并不认为这有助于减少阻塞,因为它们彼此之间没有依赖关系。我有多个线程同时运行这两个方法,当我使用lock对象和this关键字时,性能非常相似。 有人可以帮助解释我的困惑吗?喜欢用一个例子来说明差异。 除了这里的讨论,这篇文章也帮助澄清了我的疑虑。要点:将sy

  • 请看下面给我带来麻烦的方法: 然后是run方法:

  • 问题内容: 我想知道如果在同一个对象上同步两次,在Java中是否会出现任何奇怪的行为? 场景如下 两种方法都使用该对象并对其进行同步。当第一个方法调用第二个方法时,它会被锁定而停止吗? 我不这么认为,因为它是同一个线程,但是我不确定是否可能会出现其他任何奇怪的结果。 问题答案: 同步块使用 可重入 锁,这意味着如果线程已经持有该锁,则它可以重新获取它而不会出现问题。因此,您的代码将按预期工作。 请

  • 我正在寻找有关同步块的澄清。考虑一下这个类 - A是单例。getValue在整个应用程序中被多个线程大量访问。我添加了一个新方法remove,它从映射中删除一个键。如果如上所述执行删除, 当线程位于remove方法的同步块中时,我假设它将获取map对象上的锁。这是否意味着其他试图通过getValue方法访问映射的线程将被阻止?(我希望他们这样做。) 当remove方法的同步块中没有线程时,访问ge

  • 问题内容: 代码段-1 代码段-2 我在第一个代码段中遇到了竞争。我知道这是因为我正在获得对不可变对象(类型为Integer)的锁定。 我已经写了第二个代码片段,这再次使“布尔”不变。但这有效(输出运行中不显示竞争条件)。如果我正确理解了上一个问题的解决方案,则以下是出现问题的一种可能方法 线程1锁定由指向的对象(例如A) 线程2现在试图获取由指向的对象的锁,并进入A的等待队列。 线程1进入同步块