【问题标题】:At what point is the lock really released after calling notify()调用 notify() 后什么时候才真正释放锁
【发布时间】:2018-10-14 11:34:07
【问题描述】:

我有检查过的代码,我只想知道我的理解是否正确。我有以下两个课程

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() 的同步块完成。这是正确的还是有任何其他非确定性行为。

【问题讨论】:

    标签: java multithreading synchronized


    【解决方案1】:

    Javadoc for the Object.notifyAll method 非常清楚这个话题:

    (我加粗的文字)

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

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

    【讨论】:

    • 所以这意味着等待线程需要等到同步块完成,即使调用了 notify()。谢谢
    • @Shamitha:等待线程必须重新获取它在开始等待时释放的锁,在释放锁之前它无法继续。
    【解决方案2】:

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

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

    这几乎是o.notify() 所做的唯一 事情。事实上,如果等待o.notify() 的线程队列是空的,那么o.notify() 根本不会做任何事情。

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-14
        • 2021-11-18
        • 2015-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多