2

我想了解java中的同步块的概念。 截至我已阅读的文档中,我明白如果我们获取 锁(使用实例变量的同步块),那么我们 无法获取该类中同一对象的同步锁。但 当我尝试使用以下代码片段时,发现我的 理解出错了。JAVA同步对象在不同的​​方法

即,我可以同时在两个不同的 方法中获取锁 (同一个实例变量上的同步块)。当线程启动时,它将运行 方法并无限期地等待并且不会从同步的 块中跑出。同时,如果我使用相同的 线程调用停止方法,它将进入同步块并执行通知 语句。我在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(); 
    } 
} 

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

+0

你可以请你分享你的代码如何创建线程? – Lathy

+0

这是不是多线程..你的程序是一个单线程与主线程运行后面 – Lathy

回答

1

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

这是相关的API doc for Object#wait,第二段涵盖了我上面介绍的关于如何等待解锁的内容。注意它说你必须在一个循环中调用这个方法的部分,否则你有一个订单相关性错误,当另一个线程可以开始等待之前,通知到达主线程时可能导致等待线程挂起。

公共最终空隙等待() 抛出InterruptedException的

造成当前线程等待,直到其他线程调用 notify()方法或此对象的notifyAll的()方法。在其他 单词中,此方法的行为与其仅执行呼叫 wait(0)完全相同。

当前线程必须拥有该对象的监视器。该线程发布 该监视器的所有权,并等待另一个线程通知 等待此对象监视器的线程通过调用notify方法或notifyAll方法的 唤醒。然后线程 等待,直到它可以重新获得显示器的所有权并恢复执行 。

如在一个参数的版本,中断和杂散唤醒是 可能的,并且这种方法应该总是在一个循环中使用:

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

此方法应该仅由一个线程是所有者被称为 此对象的监视器。有关 线程可以成为监视器所有者的说明,请参阅notify方法。

了解这是一个玩具的例子,但子类的线程和重写线程方法是混淆。使用Runnable而不是Thread的原因之一是不会因错误地覆盖Thread方法而导致问题。

+0

我对synchronized块的怀疑被清除了。感谢您的解释@Nathan Hughes – Rock

+0

@Rock请记住注意,并在满意答案时将答案标记为正确。真正的精神:) –

-2

这是多线程的,它可能永远等不到。 在你的情况你很幸运,_myclassAdmin.stop();在MyClass开始执行并执行wait()后执行;

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

要获得一致的行为做一两件事,在主像放了1秒睡两个方法调用之间:现在

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

,执行将始终停止。另外,当一个线程调用wait()时,它释放与之关联的监视器,因此任何其他线程都可以获得该锁并发出notify()/ notifyAll()以唤醒等待的线程。这是期望

+1

Downvoted为不好的建议添加睡眠方法。处理这个问题的正确方法是使用带有条件变量的循环,如文档中所述。 –