首页常见问题正文

为什么说Synchronized是非公平锁?

更新时间:2023-04-11 来源:黑马程序员 浏览量:

IT培训班

  Synchronized是一种独占锁(也称为互斥锁),在Java中用于保护共享资源的并发访问。Synchronized 可以保证同一时刻只有一个线程可以获取到锁,从而避免了多个线程同时修改共享资源的问题。然而,Synchronized 是一种非公平锁,因为它不能保证先请求锁的线程先获取锁。

  当多个线程同时请求一个 Synchronized 锁时,这些线程会被放入一个等待队列中,等待获取锁。在某个时刻,只有一个线程会从等待队列中被选择并获得锁,而其他线程仍然需要等待。如果在这个时刻选择等待时间最长的线程获得锁,那么就是公平锁。但是,Synchronized 是一种非公平锁,它选择要获得锁的线程是随机的,而不考虑等待时间的长短。这就意味着一个线程可能会连续获取到锁,而其他线程需要一直等待,这就造成了线程的不公平竞争。

  下面是一个使用Synchronized的示例代码,它模拟了一个银行账户并发存取的情况:

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进行修改。然而,如果有多个线程同时访问这个银行账户,并且每个线程都不断地执行存款和取款操作,那么就会出现线程的竞争,而这种竞争的结果是不公平的,因为Synchronized不保证先请求锁的线程先获得锁。

  为了说明Synchronized是一种非公平锁,我们可以修改上面的代码,在deposit和withdraw方法中添加一些延迟,让不同的线程在不同的时间请求锁。然后运行多个线程并观察它们执行的顺序和结果。

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();
        }
    }
}

  在上面的代码中,我们创建了5个线程并让它们同时对一个银行账户进行存款和取款操作。每个线程执行3 次操作,每次操作后都会让线程睡眠100毫秒。这样做的目的是让不同的线程在不同的时间请求锁,以模拟实际的并发场景。

  运行上面的代码,可以得到类似下面的输出:

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...

  从输出可以看出,不同的线程交替执行,但有些线程连续执行了多次,而其他线程则需要等待很长时间才能获得锁。这就说明了Synchronized是一种非公平锁,它不能保证先请求锁的线程先获取锁。

分享到:
在线咨询 我要报名
和我们在线交谈!