簡體   English   中英

java:可以同步塊交錯嗎?

[英]java: can synchronized block interleave?

使用此代碼,我有一個意外的(至少對我來說)輸出

public class Test {
    static boolean condition = false;

    void runme() {
        var reader = new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    System.out.println("waiting for condition");
                    while (!condition) {}
                    System.out.println("condition is true");
                }
            }
        };

        var writer = new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    System.out.println("condition is set to true");
                    condition = true;
                }
            }
        };

        new Thread(reader).start();
        new Thread(writer).start();

    }

    public static void main(String[] args) {
        new Test().runme();
    }
}

根據文檔,如果reader對象首先啟動,我預計會出現死鎖

  1. this獲取鎖(進入同步塊)
  2. 打印“等待條件”
  3. 永遠陷入無限循環
  4. 另一個線程等待this鎖,進入它自己的同步塊

但是,在某些代碼運行中,我得到了輸出

waiting for condition
condition is set to true
condition is true

我錯過了什么或者我誤解了同步塊/方法是如何工作的?

兩個synchronized (this)語句引用Runnable匿名類。
因此,兩個Runnable實例的同步不會在同一個鎖上運行。
您必須在外部類實例上進行同步才能鎖定同一監視器,例如:

synchronized (Test.this) {...}

另外,請注意通過使用lambda來實現Runnable功能接口,例如:

var writer = () -> {
    synchronized (this) {
        System.out.println("condition is set to true");
        condition = true;
    }
};

你可以保持實際語法( synchronized (this) )作為this在這種情況下並不是指不存在,而是指外實例的匿名類。

在您的代碼中, synchronized(this)引用兩個不同的對象。 所以兩個代碼都不會阻塞另一個,它們只是同時運行。

另一種看待它的方法是不使用var或local類。 只需聲明兩個與readerwriter完全相同的頂級類:

//       var reader = new Runnable() {
class Reader implements Runnable {
        @Override
        public void run() {
            synchronized (this) {
                System.out.println("waiting for condition");
                while (!condition) {}
                System.out.println("condition is true");
            }
        }
    }


//        var writer = new Runnable() {
class Writer implements Runnable {
        @Override
        public void run() {
            synchronized (this) {
                System.out.println("condition is set to true");
                condition = true;
            }
        }
    }

它應該是很明顯, this在這種情況下指的是每個類,而不是同一對象的一個實例,因此這兩類永遠無法阻止對方。

引用this是指當前對象。 在內部類的實例方法中, this指的是內部類的當前對象。 如果你想訪問外部封閉類的當前對象,那么你需要使用: OuterClassName.this

在您的情況下,您有兩個具有匿名類的單獨對象。 同步塊不共享要鎖定的公共對象,因此實際上沒有同步,而是兩個線程獨立並行運行。

暫無
暫無

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

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