首頁常見問題正文

為什么說Synchronized是非公平鎖?

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

IT培訓(xùn)班

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

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

  下面是一個(gè)使用Synchronized的示例代碼,它模擬了一個(gè)銀行賬戶并發(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修飾的,以確保同時(shí)只有一個(gè)線程可以對(duì) balance進(jìn)行修改。然而,如果有多個(gè)線程同時(shí)訪問這個(gè)銀行賬戶,并且每個(gè)線程都不斷地執(zhí)行存款和取款操作,那么就會(huì)出現(xiàn)線程的競爭,而這種競爭的結(jié)果是不公平的,因?yàn)镾ynchronized不保證先請(qǐng)求鎖的線程先獲得鎖。

  為了說明Synchronized是一種非公平鎖,我們可以修改上面的代碼,在deposit和withdraw方法中添加一些延遲,讓不同的線程在不同的時(shí)間請(qǐng)求鎖。然后運(yùn)行多個(gè)線程并觀察它們執(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個(gè)線程并讓它們同時(shí)對(duì)一個(gè)銀行賬戶進(jìn)行存款和取款操作。每個(gè)線程執(zhí)行3 次操作,每次操作后都會(huì)讓線程睡眠100毫秒。這樣做的目的是讓不同的線程在不同的時(shí)間請(qǐng)求鎖,以模擬實(shí)際的并發(fā)場(chǎng)景。

  運(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í)行了多次,而其他線程則需要等待很長時(shí)間才能獲得鎖。這就說明了Synchronized是一種非公平鎖,它不能保證先請(qǐng)求鎖的線程先獲取鎖。

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