我试图理解java中synchronized块的概念 . 至于我读过的文档,我明白如果我们获取一个锁(使用实例变量的同步块),那么我们就无法在该类中的同一个对象上获取同步锁 . 但是,当我尝试使用以下代码段时,我发现我的理解是错误的 .
即我能够同时在两种不同的方法中获取锁(同一实例变量上的同步块) . 当线程启动时,它将转到run方法并无限期地等待,并且不会从synchronized块中出来 . 同时,如果我使用相同的线程调用stop方法,它将进入synchronized块并执行notify语句 . 我在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方法中的synchronized块) . 当我调用stop方法时,它应该无限期地等待,直到run方法从synchronized块中出来(在这种情况下永远不会发生) . 但是当我执行时,调用stop方法获取对'lock'对象的锁定并通知导致该线程关闭的对象 .
2 回答
这是多线程的,它可能永远等待可能不会 . 在你的情况下,你很幸运_myclassAdmin.stop();在MyClass开始执行并执行wait()之后执行;
我将方法stop()名称更改为stop1()之后运行程序,它正在等待 .
为了获得一致的行为做一件事,在主要的两个方法调用之间放一个1秒的睡眠,如:
现在,执行将永远停止 .
此外,当一个线程调用wait()时,它释放与之关联的监视器,因此任何其他线程都可以获取该锁并发出notify()/ notifyAll()来唤醒等待的线程 . 这是期待的
您的两种方法都使用相同的锁 . 如果你的MyClass线程在主线程可以调用stop方法之前开始等待,你的stop方法仍然可以继续,因为等待的线程允许锁定 . 一旦线程进入wait方法,它就会在它进入休眠状态之前释放锁,并且在它退出wait方法之前不会重新获取锁 .
这是相关的API doc for Object#wait,第二段涵盖了我上面描述的等待释放锁的方法 . 注意它必须在循环中调用此方法的部分,否则您有一个顺序依赖性错误,当通知到达主线程之前,其他线程可以开始等待时,可能导致等待线程挂起 .
理解这是一个玩具示例,但子类化Thread和重写Thread方法令人困惑 . 使用Runnable而不是Thread的原因之一是,错误地覆盖Thread方法不会导致问题 .