MST

星途 面试题库

面试题:Java中如何自定义实现一个公平的可重入锁

假设你需要在Java中自定义实现一个锁机制,要求该锁既是可重入的又是公平的。请描述实现思路,并给出关键代码片段。
13.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 使用AQS(AbstractQueuedSynchronizer)框架:AQS是Java并发包中实现同步器的基础框架。通过继承AQS,并重写其几个关键方法来实现自定义锁。
  2. 可重入性:在获取锁时,记录当前持有锁的线程以及重入次数。当持有锁的线程再次获取锁时,增加重入次数而不是阻塞。
  3. 公平性:AQS内部维护一个FIFO队列来管理等待获取锁的线程。在获取锁时,判断当前队列是否有等待线程,如果有则按照队列顺序分配锁。

关键代码片段

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class CustomFairReentrantLock implements Lock {
    // 自定义同步器
    private static class Sync extends AbstractQueuedSynchronizer {
        // 判断是否持有锁
        protected boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        // 尝试获取锁
        public boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // 公平性判断,队列中无等待线程时才能获取锁
                if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 可重入
            else if (current == getExclusiveOwnerThread()) {
                setState(c + acquires);
                return true;
            }
            return false;
        }

        // 尝试释放锁
        protected boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        // 获取条件变量
        Condition newCondition() {
            return new ConditionObject();
        }
    }

    private final Sync sync = new Sync();

    // 获取锁
    @Override
    public void lock() {
        sync.acquire(1);
    }

    // 可中断地获取锁
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    // 尝试获取锁
    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    // 在指定时间内尝试获取锁
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    // 释放锁
    @Override
    public void unlock() {
        sync.release(1);
    }

    // 获取条件变量
    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
}