首頁常見問題正文

為什么說Synchronized是非公平鎖?

更新時間:2023-04-11 來源:黑馬程序員 瀏覽量:

IT培訓(xùn)班

  Synchronized是一種獨(dú)占鎖(也稱為互斥鎖),在Java中用于保護(hù)共享資源的并發(fā)訪問。Synchronized 可以保證同一時刻只有一個線程可以獲取到鎖,從而避免了多個線程同時修改共享資源的問題。然而,Synchronized 是一種非公平鎖,因?yàn)樗荒鼙WC先請求鎖的線程先獲取鎖。

  當(dāng)多個線程同時請求一個 Synchronized 鎖時,這些線程會被放入一個等待隊(duì)列中,等待獲取鎖。在某個時刻,只有一個線程會從等待隊(duì)列中被選擇并獲得鎖,而其他線程仍然需要等待。如果在這個時刻選擇等待時間最長的線程獲得鎖,那么就是公平鎖。但是,Synchronized 是一種非公平鎖,它選擇要獲得鎖的線程是隨機(jī)的,而不考慮等待時間的長短。這就意味著一個線程可能會連續(xù)獲取到鎖,而其他線程需要一直等待,這就造成了線程的不公平競爭。

  下面是一個使用Synchronized的示例代碼,它模擬了一個銀行賬戶并發(fā)存取的情況:

public class BankAccount {
    private int balance;
    
    public synchronized void deposit(int amount) {
        balance += amount;
    }
    
    public synchronized void withdraw(int amount) {
        balance -= amount;
    }
}

  在上面的代碼中,deposit和withdraw方法都是使用Synchronized修飾的,以確保同時只有一個線程可以對 balance進(jìn)行修改。然而,如果有多個線程同時訪問這個銀行賬戶,并且每個線程都不斷地執(zhí)行存款和取款操作,那么就會出現(xiàn)線程的競爭,而這種競爭的結(jié)果是不公平的,因?yàn)镾ynchronized不保證先請求鎖的線程先獲得鎖。

  為了說明Synchronized是一種非公平鎖,我們可以修改上面的代碼,在deposit和withdraw方法中添加一些延遲,讓不同的線程在不同的時間請求鎖。然后運(yùn)行多個線程并觀察它們執(zhí)行的順序和結(jié)果。

public class BankAccount {
    private int balance;
    
    public synchronized void deposit(int amount) {
        System.out.println("Thread " + Thread.currentThread().getId() + " is depositing...");
        balance += amount;
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public synchronized void withdraw(int amount) {
        System.out.println("Thread " + Thread.currentThread().getId() + " is withdrawing...");
        balance -= amount;
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount account = new BankAccount();
        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                for (int j = 1; j <= 3; j++) {
                    account.deposit(100);
                    account.withdraw(50);
                }
            }).start();
        }
    }
}

  在上面的代碼中,我們創(chuàng)建了5個線程并讓它們同時對一個銀行賬戶進(jìn)行存款和取款操作。每個線程執(zhí)行3 次操作,每次操作后都會讓線程睡眠100毫秒。這樣做的目的是讓不同的線程在不同的時間請求鎖,以模擬實(shí)際的并發(fā)場景。

  運(yùn)行上面的代碼,可以得到類似下面的輸出:

Thread 14 is depositing...
Thread 14 is withdrawing...
Thread 15 is depositing...
Thread 15 is withdrawing...
Thread 14 is depositing...
Thread 14 is withdrawing...
Thread 15 is depositing...
Thread 15 is withdrawing...
Thread 13 is depositing...
Thread 13 is withdrawing...
Thread 12 is depositing...
Thread 12 is withdrawing...
Thread 13 is depositing...
Thread 13 is withdrawing...
Thread 12 is depositing...
Thread 12 is withdrawing...
Thread 11 is depositing...
Thread 11 is withdrawing...
Thread 11 is depositing...
Thread 11 is withdrawing...

  從輸出可以看出,不同的線程交替執(zhí)行,但有些線程連續(xù)執(zhí)行了多次,而其他線程則需要等待很長時間才能獲得鎖。這就說明了Synchronized是一種非公平鎖,它不能保證先請求鎖的線程先獲取鎖。

分享到:
在線咨詢 我要報(bào)名
和我們在線交談!