调用 notify() 后,锁在什么时候真正释放



我检查了代码,我只想知道我的理解是否正确。我有以下两类

public class WaitCheckWaiter implements Runnable
{
WaitCheck wc;
public WaitCheckWaiter( WaitCheck wc )
{
this.wc = wc;
}
@Override
public void run()
{
synchronized ( wc.strList )
{
wc.strList.add( "Added" );
System.out.println( "Notify for others" );
wc.strList.notifyAll();
for ( int i = 0; i < 100; i++ )
{
System.out.println( i );
}
try
{
Thread.sleep( 5000 );
}
catch ( InterruptedException e )
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println( "Woke up" );
System.out.println( "After Notifying" );
}
System.out.println( "After synch WaitCheckWaiter" );
}
}

然后下面的这个

public class WaitCheck implements Runnable{
WaitCheck wc;
List<String> strList = new ArrayList();
public static void main(String[] args) {
WaitCheck wc = new WaitCheck();
new Thread(wc).start();
WaitCheckWaiter wcw = new WaitCheckWaiter(wc);
new Thread(wcw).start();
}

@Override
public void run() {
synchronized (strList) {
if(strList.size() == 0)
{
try {
System.out.println("Just Before wait..");
strList.wait();
System.out.println("Just after wait..");
// printing the added value
System.out.println("Value : "+strList.get(0));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
System.out.println("In else statement..!!");
}
}
System.out.println("After synch WaitCheck");
}
}

所以我的理解是,即使我调用 notifyAll((,等待线程也无法恢复,直到同步块完成,称为 notifyAll((。这是对的还是有任何其他非确定性行为。

Object.notifyAll方法的Javadoc在这个主题上非常清楚:

(文字由我加粗(

唤醒此对象监视器上等待的所有线程。一个 线程通过调用其中一个等待来等待对象的监视器 方法。

唤醒的线程将无法继续,直到 当前线程放弃此对象的锁。觉醒者 线程将以通常的方式与任何其他线程竞争 可能正在积极竞争以在此对象上进行同步;为 例如,唤醒的线程不享有可靠的特权或 作为下一个线程锁定此对象的缺点。

在大多数操作系统中,线程由一个对象表示,该对象可以根据其状态在不同的容器之间移动。 这些容器传统上称为"队列",即使它们不一定作为实际的先进先出队列实现。

当线程调用o.wait()时,它的对象从"当前正在运行"的队列移动到仅包含那些等待o.notify()的对象的队列。 当另一个线程调用o.notify()操作系统从该队列中选择一个线程,并将其移动到等待轮到它们进入(或返回到(synchronized(o)块的线程队列中。

这几乎是o.notify()唯一做的事情。 实际上,如果等待o.notify()线程队列为空,则o.notify()根本不执行任何操作。

o.notifyAll()是相同的,只是它不是只移动一个线程,而是移动所有正在等待的线程。

添加到另一个答案,来自关于 Thread.sleep(...( 的文档:

线程不会失去任何监视器的所有权。

这意味着至少作为一个基本原则,只要仍然持有任何同步锁,就永远不应该调用 Thread.sleep(...(。

最新更新