ReentrantLock分为公平锁和非公平锁,那底层分别是如何实现的

原创
05/11 16:10
阅读数 47

ReentrantLock在Java中是通过AbstractQueuedSynchronizer(AQS)框架实现的,它提供了公平锁(FairSync)和非公平锁(NonfairSync)两种模式。这两种锁的实现主要区别在于获取锁的策略。

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {

    // 非公平锁
    private static final ReentrantLock nonFairLock = new ReentrantLock();

    // 公平锁
    private static final ReentrantLock fairLock = new ReentrantLock(true); // 传入true参数表示使用公平锁

    public static void main(String[] args) {
        //demonstrateLock(nonFairLock, "Non-Fair Lock");
        demonstrateLock(fairLock, "Fair Lock");
    }

    private static void demonstrateLock(ReentrantLock lock, String lockType) {
        class Task implements Runnable {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    lock.lock();
                    try {
                        System.out.println(Thread.currentThread().getName() + " acquired " + lockType + ", iteration: " + i);
                        Thread.sleep(10); // 模拟持有锁时的工作
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }

        Thread t1 = new Thread(new Task(), "Thread-1");
        Thread t2 = new Thread(new Task(), "Thread-2");

        t1.start();
        t2.start();

        try {
            t1.join(); // 等待所有线程完成
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 公平锁(FairSync)的实现:

公平锁在尝试获取锁时,会首先检查队列中是否有其他等待的线程。如果有其他线程已经在等待队列中,那么新来的线程就会加入到队列的末尾排队等待,而不是尝试直接获取锁。这样可以确保线程按照它们请求锁的顺序来获取锁,体现了公平性。公平锁的实现步骤大致如下:

1. 调用`lock()`方法时,首先通过CAS操作尝试快速获取锁。
2. 如果失败,检查AQS的等待队列中是否已经有线程在等待。如果有,当前线程就加入到队列末尾等待,不会进行进一步的尝试。
3. 当前线程会进入阻塞状态,直到被AQS唤醒,通常是前一个持有锁的线程释放锁并唤醒它。

### 非公平锁(NonfairSync)的实现:

非公平锁在尝试获取锁时,不管队列中是否有其他线程在等待,总是会先尝试直接通过CAS操作快速获取锁,这可能导致新来的线程“插队”,获得锁的机会优于已经在队列中等待的线程。这种设计牺牲了公平性以换取更高的吞吐量。非公平锁的实现步骤大致如下:

1. 在`lock()`方法中,同样首先尝试通过CAS操作快速获取锁,即使此时有其他线程已经在队列中等待。
2. 如果快速获取失败,非公平锁仍然可能会继续尝试CAS获取锁,即使队列中已有等待线程。这意味着它可能在某些情况下直接获取锁,跳过队列中的其他线程。
3. 只有当多次尝试CAS获取锁都失败后,才会将当前线程加入到等待队列,并进入阻塞状态。

无论是公平锁还是非公平锁,它们都使用了AQS的内部FIFO队列来管理等待的线程,以及通过状态位(state)和等待节点(Node)来协调线程的阻塞与唤醒。此外,ReentrantLock还支持可重入特性,即已经持有锁的线程再次请求相同锁时可以直接获取,而不需要再次排队。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部