likes
comments
collection
share

为什么Synchronized 是非公平锁?

作者站长头像
站长
· 阅读数 19

我正在参加「掘金·启航计划」

1、什么是公平锁和非公平锁

公平锁和非公平锁是指在多线程环境下,如何对锁进行获取的顺序和策略的不同。

公平锁是指多个线程按照申请锁的顺序来获取锁,即先到先得的策略。当一个线程释放锁之后,等待时间最长的线程将获得锁。公平锁的优点是保证了每个线程的公平性,不存在饥饿现象,但是由于需要维护一个等待队列,因此会增加系统的开销。

非公平锁是指多个线程获取锁的顺序是不确定的,不一定按照申请锁的顺序来获取锁。当一个线程释放锁之后,锁的获取是由系统的调度算法来决定的。非公平锁的优点是可以减少线程上下文切换的开销,提高系统的吞吐量,但是容易出现饥饿现象,即某些线程可能会一直获取不到锁。

一般来说,公平锁适用于对线程公平性要求比较高的场景,而非公平锁适用于对性能要求比较高的场景。但是在具体应用时,需要根据实际情况来选择合适的锁。

2、Java中的公平锁和非公平锁

Java中的公平锁和非公平锁主要有以下几种:

  1. ReentrantLock的公平锁和非公平锁:ReentrantLock是Java中常用的锁实现类之一,它提供了公平锁和非公平锁两种模式。在创建ReentrantLock对象时,可以通过构造函数传入一个布尔类型的fair参数来指定锁的模式。如果fair为true,则创建公平锁;如果fair为false,则创建非公平锁。

  2. ReentrantReadWriteLock的公平锁和非公平锁:ReentrantReadWriteLock是一个读写锁,它也提供了公平锁和非公平锁两种模式。在创建ReentrantReadWriteLock对象时,可以通过构造函数传入一个布尔类型的fair参数来指定锁的模式。如果fair为true,则创建公平锁;如果fair为false,则创建非公平锁。

  3. StampedLock的乐观锁和悲观锁:StampedLock是Java 8中新增的一种锁实现类,它提供了乐观锁和悲观锁两种模式。在使用StampedLock时,可以通过调用tryOptimisticRead()方法来获取乐观锁,或者通过调用readLock()方法来获取悲观锁。乐观锁是一种无锁的机制,它不会阻塞线程,但是需要通过validate()方法来检查锁是否仍然有效。

  4. Synchronized的非公平锁:Synchronized是Java中内置的锁机制,它默认采用非公平锁模式。在使用Synchronized时,如果多个线程同时请求锁,则会根据系统的调度算法来决定哪个线程获取锁。

公平锁和非公平锁的性能和效率都会受到多种因素的影响,如锁的争用情况、线程的数量、系统的负载等。在实际应用中,需要根据具体情况选择合适的锁模式。

3、为什么Synchronized是非公平锁

Synchronized是Java中内置的锁机制,它的锁模式是非公平锁,这是因为Synchronized的实现方式是基于对象监视器(monitor)的。

在Java中,每个对象都有一个与之关联的monitor,当一个线程需要获取某个对象的锁时,它会首先尝试获取这个对象关联的monitor。如果monitor已经被其他线程占用,那么这个线程就会进入monitor的等待队列中,等待其他线程释放锁。

在Synchronized中,当一个线程释放锁时,JVM会从等待队列中随机选择一个线程来获取锁,而不是按照申请锁的顺序来获取锁,因此Synchronized是一种非公平锁。这种实现方式的优点是可以减少线程上下文切换的开销,提高系统的吞吐量,但是容易出现饥饿现象,即某些线程可能会一直获取不到锁。

Synchronized也可以通过在代码中使用wait()和notify()方法来实现公平锁,但是这种方式比较复杂,容易出错,而且性能也不如ReentrantLock的公平锁实现方式。因此,在实际应用中,如果需要公平锁,建议使用ReentrantLock。

4、Synchronized代码示例

下面是一个简单的Synchronized使用示例:

4.1、修饰方式

public class SynchronizedExample {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
    public static void main(String[] args) throws InterruptedException {
        SynchronizedExample example = new SynchronizedExample();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                example.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                example.increment();
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("Count: " + example.count);
    }
}

输入结果如下:

为什么Synchronized 是非公平锁?

编辑切换为居中

添加图片注释,不超过 140 字(可选)

在这个示例中,Synchronized被用于修饰increment()方法,这样在同一时刻只有一个线程可以执行该方法。这个示例中创建了两个线程,分别对count变量进行自增操作。由于Synchronized的作用,这些操作是互斥的,所以最终输出的count值应该是20000。

4.2、修饰代码块

除了修饰方法,Synchronized还可以修饰代码块。下面是一个使用Synchronized修饰代码块的示例:

public class SynchronizedExample {
    private int count = 0;
    private final Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SynchronizedExample example = new SynchronizedExample();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                example.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                example.increment();
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("Count: " + example.count);
    }
}

输出结果如下:

为什么Synchronized 是非公平锁?

编辑切换为居中

添加图片注释,不超过 140 字(可选)

在这个示例中,Synchronized被用于修饰代码块,这样在同一时刻只有一个线程可以执行该代码块。在这个示例中,lock对象被用于作为Synchronized锁的对象。

5、总结

需要注意的是,Synchronized锁的是对象,而不是代码。在同一个对象上使用Synchronized修饰的代码块或方法是互斥的,但不同对象上的Synchronized代码块或方法并不互斥。

Synchronized虽然可以保证线程安全,但是它会导致性能问题。在使用Synchronized时需要注意以下几点:

  1. 尽量缩小Synchronized的作用范围,只在必要的代码块或方法上使用Synchronized。

  2. 尽量不要在Synchronized代码块或方法中调用其他耗时的方法,这会导致其他线程长时间等待。

  3. 尽量使用Lock接口代替Synchronized,因为Lock接口提供了更灵活的锁定机制。