Lock锁源码分析

  1. Lock 接口出现之前,Java 程序是靠 synchronized 关键字实现锁功能的,而 Java SE 5之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,它提供了与synchronized 关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。

  1. Lock的简单使用:

Lock lock = new ReentrantLock();
lock.lock();
try {
} finally {
lock.unlock();
}
  1. Lock的api:

  1. Lock独占式获取锁lock()源码分析:

(1). 默认ReentrantLock()构建的是非公平锁对象,若要构建公平锁对象需要使用指定参数fair的构造方法创建。

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

(2). 公平同步器与非公平同步器均继承于父类Sync,分别实现了父类Sync的抽象方法lock(),以及重写了Sync的父类AbstractQueuedSynchronizer(抽象队列同步器)的方法tryAcquire(int acquires),lock()方法中调用的acquire(1)为AbstractQueuedSynchronizer的方法,区别在于acquire(1)的实现逻辑中调用的tryAcquire(int acquires)为各自的实现,因此,区别重点在于tryAcquire(int acquires)方法的区别上

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);
    }

    /**
     * Fair version of tryAcquire.  Don't grant access unless
     * recursive call or no waiters or is first.
     */
    protected final 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()) {
            // 可重入锁
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    /**
     * Performs lock.  Try immediate barge, backing up to normal
     * acquire on failure.
     */
    final void lock() {
        if (compareAndSetState(0, 1))    // 直接获取同步状态,不判断队列数量以及节点顺序
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);    // 该方法为父类Sync的方法,具体源码如下
    }
}

// Sync的方法:
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;
}

(3). acquire(1)的实现源码,其为Sync的父类AbstractQueuedSynchronizer:

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&    // 为(2)中的各自实现方法
        // 将节点加入到同步队列末端后开始自选,直到获取到同步状态后跳出自选,即获取到锁 
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))   
        selfInterrupt();
}

// 获取同步状态失败后,将当前线程封装为Node,放入同步队列末端
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {    // 使用compareAndSetTail将其节点放入队列末端
            pred.next = node;
            return node;
        }
    }
    enq(node);    // 将其节点放入队列末端直至成功
    return node;
}

// 将其节点放入队列末端直至成功
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

// 自选获取同步状态
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();    // 获取当前节点的前一节点
// 判断前一节点是否为头节点,并尝试获取同步状态,而这里的tryAcquire(arg)为之前重写的方法,公平与非公平
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
 // 检查线程是否中断,中断的话只修改中断状态,但是不影响继续获取同步状态,在外层selfInterrupt()进行自我中断
 // 和可中断式获取区别在于此,可中断式直接抛出异常,终止获取同步状态,后面上源码 
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
  1. Lock可中断式获取锁lockInterruptibly()源码分析:

(1). ReentrantLock中的方法:

public void lockInterruptibly() throws InterruptedException {
// 这里的sync仍然为4中源码解析的构造器中的公平同步器或非公平同步器,其重要仍在于重写的
// tryAcquire(int acquires)
    sync.acquireInterruptibly(1);
}

(2). acquireInterruptibly(1)方法源码,其为Sync的父类AbstractQueuedSynchronizer:

public final void acquireInterruptibly(int arg)
            throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            // 此处tryAcquire(arg)仍为公平同步器与非公平同步器重写
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                // 与独占式同步器的区别在于此
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

(3). 与lock()区别:

和lock()的区别在于:线程尝试获取锁操作失败后,在等待过程中,如果该线程被其他线程中断了,它是如何响应中断请求的。lock方法会忽略中断请求,继续获取锁直到成功;而lockInterruptibly则直接抛出中断异常来立即响应中断,由上层调用者处理中断

如果要求被中断线程不能参与锁的竞争操作,则此时应该使用lockInterruptibly方法,一旦检测到中断请求,立即返回不再参与锁的竞争并且取消锁获取操作(即finally中的cancelAcquire操作)

  1. 同步队列设置节点图解:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值