簡體   English   中英

Java:synchronize關鍵字不會阻止其他線程上的對象

[英]Java: synchronize keyword doesn't block object on different thread

public class SynchronizeTest {

    public synchronized void methodA() {
        System.out.println("calling method a ...");
        sleep(2000);
        System.out.println("ending method a");
    }

    public void methodC() {
        System.out.println("calling method C");
        new Thread(new Runnable() {
            @Override
            public void run() {
                methodA();
            }
        }).start();
        sleep(100);
        System.out.println("end method C");
    }

    public static void main(String[] args) {
        new SynchronizeTest().methodC();
    }


    static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

起初,我猜是因為我synchronize方法A,這意味着整個對象將被鎖定,直到該方法完成為止。 所以答案應該是:

calling method C
calling method a
ending method a
ending method C

但是事實證明,結果是這樣的:

calling method C
calling method A
ending method C
ending method A

這意味着methodA不會像我猜的那樣鎖定對象。 請告訴我為什么。

在實例方法上使用synchronized關鍵字時,這意味着該對象上的方法當時只能由一個線程調用。

這並不意味着對對象的所有方法進行任何形式的鎖定,即可以在該方法的調用期間調用其他實例方法-當您在執行操作時異步調用它時,也更容易。

既然你是你的線程內調用它methodC ,並在睡眠時間methodA比結束前的一個更大的methodC ,您的電流輸出是非常可能發生的每一次。

這是相關的文檔報價(請參閱此處的頁面):

使得方法同步具有兩個作用:

  • 首先,不可能在同一對象上兩次調用同步方法。 當一個線程正在執行對象的同步方法時,所有其他調用同一對象塊的同步方法的線程(掛起執行),直到第一個線程對該對象完成。

  • 其次,當同步方法退出時,它會自動建立與先后發生的關系,並隨后對同一對象調用同步方法。 這保證了對象狀態的更改對所有線程都是可見的。

注意

您可能需要join調用methodA的線程,以確保在執行methodC的最后一條語句之前終止其執行。

首先,您有2個線程1)main和2)您創建的線程(假設為thread1)。 現在發生的事情是使methodA同步,因此當線程1到達那里時它將保留在該方法中並嘗試完成執行,但同時主線程可以進一步處理並打印最后的C語句。因為您在方法中添加了sleep調用,這導致thread1睡眠2秒。 所以輸出將是C(主線程),a(您的線程),C(主線程),a(您的線程)

請閱讀以下內容: https : //docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html如前所述,不可能對同一對象的兩次同步方法調用進行交織。 當一個線程正在執行對象的同步方法時,所有其他調用同一對象塊的同步方法的線程(掛起執行),直到第一個線程對該對象完成。 這意味着該對象將被其他同步方法鎖定。 同步methodC也不是一個好主意。 它將為您提供以下輸出:調用方法C /調用方法a /結束方法a /結束方法C。為了獲得所需的輸出,可以使用以下代碼:

public class SynchronizeTest implements Runnable{

    public synchronized void methodA() throws InterruptedException {
        System.out.println("calling method a ...");
        Thread.sleep(2000);
        System.out.println("ending method a");
        this.notify();
    }

    public synchronized void methodC() throws InterruptedException {
        System.out.println("calling method C");
        new Thread(new Runnable() {
            @Override
            public void run() {
                methodA();
            }
        }).start();
        this.wait();
        System.out.println("end method C");
    }

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

    @Override
    public void run() {
        // TODO Auto-generated method stub

    }
}

關鍵字synchronized意味着防止不同線程使用相同變量時發生的錯誤。 鎖定線程根本沒有任何意義,因為您可以隨后調用方法。

暫無
暫無

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

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