锁 - 公平 vs 非公平

2022-11-22  本文已影响0人  面向对象架构

公平锁 非公平锁

公平锁

典型的公平锁:ReentrantLock(true)

多个线程按照申请锁的顺序来获取锁。

作用:严格按照线程启动的顺序来执行,不允许其他线程插队执行。

优点:等待锁的线程不会饿死。

缺点:整体吞吐效率相对非公平锁要低,等待队列中除第一个线程以外的所有线程都会阻塞,CPU唤醒阻塞线程的开销比非公平锁大。

非公平锁

典型的非公平锁:ReentrantLock(false)、synchronized

多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。

对于Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。
对于Synchronized而言,也是一种非公平锁。由于其并不像ReentrantLock是通过AQS的来实现线程调度,所以并没有任何办法使其变成公平锁。
上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式。

作用:线程启动允许插队的。

优点:可以减少唤起线程的开销,吞吐量比公平锁大。,因为线程有几率不阻塞直接获得锁,CPU不必唤醒所有线程。

缺点:处于等待队列中的线程可能会饿死,或者等很久才会获得锁。

    // 公平锁
    // 在公平锁中,获得锁的方法tryAcquire中多了 !hasQueuedPredecessors()判断。
    protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // hasQueuedPredecessors 这个方法就是最大区别所在
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }
 
    // 非公平锁
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // 区别重点看这里
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }
从图上就可以清晰看出公平和非公平的区别

比较

1.非公平锁的效率高于公平锁。

2.非公平锁并非真正随机,其获取锁还是有一定顺序的。

3.究竟公平与非公平有何区别呢?

a、若在释放锁的时候总是没有新的兔子来打扰,则非公平锁等于公平锁;

b、若释放锁的时候,正好一个兔子来喝水,而此时位于队列头的兔子还没有被唤醒(因为线程上下文切换是需要不少开销的),此时后来的兔子则优先获得锁,成功打破公平,成为非公平锁;

4.非公平锁的效率为何高于公平锁呢?

上文说到的线程切换的开销,其实就是非公平锁效率高于公平锁的原因,因为非公平锁减少了线程挂起的几率,后来的线程有一定几率逃离被挂起的开销。

上一篇下一篇

猜你喜欢

热点阅读