簡體   English   中英

奇怪的 java 等待/通知行為

[英]Strange java behavior of wait/notify

我發現 java 並發的奇怪行為。 請參閱下面的下一個代碼:

public class Test {
    static CountDownLatch latch = new CountDownLatch(1);
    public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException {
        final Thread t = new MyThread();
        t.start();
        synchronized (t) {
            latch.countDown();
            System.out.println("got to sleep");
            t.wait();
            System.out.println("wake up");
        }
    }

    static class MyThread extends Thread {
        @Override
        public void run() {
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this) {
                System.out.println("inside run");
//                notifyAll();
            }
        }
    }
}

在我看來,這段代碼應該掛起並永遠等待,但是代碼已經完成,控制台中的 next out 沒有任何問題:

got to sleep
inside run
wake up

我試圖找到一些有關在線程死亡時通知鎖的信息,但缺少這些信息。 我也沒有在 java 規范中找到任何信息。

但是,如果我嘗試鎖定其他一些 object(不是線程對象),它會像我預期的那樣工作正常。

這是因為你正在等待一個Thread實例。 Thread內部使用wait / notify / notifyAll ,所以你不應該自己這樣做 - 你會混淆Thread ,而Thread會讓你感到困惑。 特別是,當一個線程退出時,它會調用this.notifyAll()

Thread.join的文檔:

此實現使用this.wait調用this.isAlive 當一個線程終止時,將調用this.notifyAll方法。 建議應用程序不要在Thread實例上使用waitnotifynotifyAll

通常,嘗試鎖定並等待沒有其他任何東西可以與之交互的對象。 這樣你可以推斷出對象上存在的與並發相關的操作,因為它們非常有限。 只要任意代碼可以在對象上同步(以及調用wait / notify等),就很難證明您的代碼是正確的。 這就是為什么你經常會看到這樣的東西:

public class Foo {
    private final Object lock = new Object();

    ... code which uses synchronized(lock) ...
}

正如Jon Skeet所寫,在Thread對象上進行同步是個壞主意,請使用另一個:

public class Test {
    static CountDownLatch latch = new CountDownLatch(1);
    static final Object sync = new Object();

    public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException {
        final Thread t = new MyThread();
        t.start();
        synchronized (sync) {
            latch.countDown();
            System.out.println("got to sleep");
            sync.wait();
            System.out.println("wake up");
        }
    }
}

static class MyThread extends Thread {
    @Override
    public void run() {
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (sync) {
            System.out.println("inside run");
            //sync.notifyAll();
        }
    }
}

現在這個代碼永遠不會結束,直到你取消注釋sync.notifyAll();

由於在 Thread 實例上進行了鎖定,因此它的行為有所不同,如果您鎖定不同的 object(或者可能是 Object obj),那么它將正常工作,即不會打印wake up並且主線程將等待。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM