AQS之公平锁和非公平锁

Lock接口

Sychronized利用JVM指令级别的monitor锁,来实现线程安全不同的是,Lock接口实现线程安全则是代码级别实现的,Lock接口是 Java并发编程中很重要的一个接口,当程序发生异常时,Sychronized可以自动释放锁,但Lock必须需要手动解锁。与 Lock 关联密切的锁有 ReetrantLock 和 ReadWriteLock。我们以ReentrantLock切入,来看看其底层涉及到的原理。

初识ReentrantLock

ReentrantLock也叫重入锁,我们首先得了解ReentrantLock的一般使用方法:

Lock lock = new ReentrantLock(false);
lock.lock();
try{
    //临界区,执行一些具体操作。。
}finally{
    lock.unlock();
}

代码层次必须要手动解锁。

公平锁和非公平锁

查看ReentrantLock的源码可以发现:

public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();

}

当参数fair为true表示公平锁,创建的是FairSync类;false为非公平锁,创建的是NonfairSync类。如果该参数不填,则默认是非公平锁,调用另一个构造方法。

  1. 那什么是公平锁和非公平锁?

  • 公平锁:每个线程获取锁的顺序是按照线程访问锁的先后顺序获取的,最前面的线程总是最先获取到锁,遵循先来先得的规则。

  • 非公平锁:每个线程获取锁的顺序是随机的,并不会遵循先来先得的规则,所有线程会竞争获取锁

我们接下来举个例子来看看:首先创建公平锁,开启6个线程执行,分别加锁和释放锁并打印线程名的操作:

public class FairReentrantLockTest {
    static Lock lock = new ReentrantLock(true);
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                lock.lock();
                    System.out.println("临界区的当前线程名称:" + Thread.currentThread().getName());
                lock.unlock();

            }).start();
        }
    }
}

结果:

临界区的当前线程名称:Thread-0
临界区的当前线程名称:Thread-1
临界区的当前线程名称:Thread-2
临界区的当前线程名称:Thread-3
临界区的当前线程名称:Thread-4
临界区的当前线程名称:Thread-5

如果我们把公平锁换成非公平锁的话,static Lock lock = new ReentrantLock(false),再执行一遍结果为:

临界区的当前线程名称:Thread-0
临界区的当前线程名称:Thread-5
临界区的当前线程名称:Thread-1
临界区的当前线程名称:Thread-2
临界区的当前线程名称:Thread-3
临界区的当前线程名称:Thread-4

我们可以发现:当使用公平锁,线程获取锁的话,线程进入"等待队列"的队尾,得排队,依次获取锁,先到先得。如果使用的是非公平锁,那就直接尝试竞争锁,竞争得到,就获得锁,获取锁的顺序是随机的。

  1. 公平锁和非公平锁的优缺点?

  • 公平锁,其优点:所有的线程都能得到资源,不会饿死在队列中;缺点:吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,线程 每次从阻塞恢复到运行状态 都需要从用户态转换成内核态,而这个状态的转换是比较慢的,因此公平锁的执行速度会比较慢,而且CPU唤醒阻塞线程的开销会很大。

  • 非公平锁,其优点:不遵守先到先得的原则,CPU不必取唤醒所有线程,会减少唤起线程的数量,可以减少CPU唤醒线程的开销,整体的吞吐效率会高点。缺点:但这样也可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,导致"饿死"。

我们这里贴一下公平锁和非公平锁的性能测试结果图,来源于《Java并发编程实战》:

图片

从上述结果可以看出,使用非公平锁的性能(吞吐率)普遍比公平锁高很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值