concurrent互斥锁ReentrantLock & 源码分析

Posted 人生如逆旅,我亦是行人。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了concurrent互斥锁ReentrantLock & 源码分析相关的知识,希望对你有一定的参考价值。

参考文档:
Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock:http://www.cnblogs.com/skywang12345/p/3496101.html

ReentrantLock介绍

ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”
ReentrantLock分为“公平锁”和“非公平锁”。它们的区别体现在获取锁的机制上是否公平。ReentraantLock是通过一个FIFO的等待队列来管理获取该锁所有线程的
公平锁:线程依次排队获取锁
非公平锁:在锁是可获取状态时,不管自己是不是在队列的开头都会获取锁

ReentrantLock函数列表

// 创建一个 ReentrantLock ,默认是“非公平锁”。
ReentrantLock()
// 创建策略是fair的 ReentrantLock。fair为true表示是公平锁,fair为false表示是非公平锁。
ReentrantLock(boolean fair)

// 查询当前线程保持此锁的次数。
int getHoldCount()
// 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。
protected Thread getOwner()
// 返回一个 collection,它包含可能正等待获取此锁的线程。
protected Collection<Thread> getQueuedThreads()
// 返回正等待获取此锁的线程估计数。
int getQueueLength()
// 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
protected Collection<Thread> getWaitingThreads(Condition condition)
// 返回等待与此锁相关的给定条件的线程估计数。
int getWaitQueueLength(Condition condition)
// 查询给定线程是否正在等待获取此锁。
boolean hasQueuedThread(Thread thread)
// 查询是否有些线程正在等待获取此锁。
boolean hasQueuedThreads()
// 查询是否有些线程正在等待与此锁有关的给定条件。
boolean hasWaiters(Condition condition)
// 如果是“公平锁”返回true,否则返回false。
boolean isFair()
// 查询当前线程是否保持此锁。
boolean isHeldByCurrentThread()
// 查询此锁是否由任意线程保持。
boolean isLocked()
// 获取锁。
void lock()
// 如果当前线程未被中断,则获取锁。
void lockInterruptibly()
// 返回用来与此 Lock 实例一起使用的 Condition 实例。
Condition newCondition()
// 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
boolean tryLock()
// 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
boolean tryLock(long timeout, TimeUnit unit)
// 试图释放此锁。
void unlock()
View Code

举个栗子

public class ConditionTest {
    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    public static void main(String[] args) {
        ThreadA ta = new ThreadA("t");
        lock.lock(); // 获取锁
        try {
            System.out.println(Thread.currentThread().getName() + " start ta");
            ta.start();
            System.out.println(Thread.currentThread().getName() + " block");
            condition.await(); // 等待
            System.out.println(Thread.currentThread().getName() + " continue");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    static class ThreadA extends Thread {
        public ThreadA(String name) {
            super(name);
        }

        public void run() {
            lock.lock(); // 获取锁
            try {
                try {
                    Thread.sleep(1000*5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " wakup others");
                condition.signalAll(); // 唤醒“condition所在锁上的其它线程”
            } finally {
                lock.unlock(); // 释放锁
            }
        }
    }
}
View Code

源码分析

lock-公平锁(FairSync extends Sync)

 final void lock() {
            acquire(1);
        }
protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {// c=0 说明没有其他线程占有锁
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {// 队列中没有其他线程在等待锁,而且CAS把state设置成入参的值成功,这里是1(这里的CAS就是我
// 们前文提的并发竞争机制),则当前线程获取锁成功并将owner线程设置为当前线程
                    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;
        }

lock-非公平锁(NonfairSync extends Sync)

 final void lock() {
            if (compareAndSetState(0, 1))//先去cas设置锁
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);//获取锁失败,再try
        }
 protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
 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;
        }

unlock (公平锁和非公平锁的实现是一样的)

 public void unlock() {
        sync.release(1);
    }
public final boolean release(int arg) {
/*
 尝试释放锁如果失败,直接返回失败,如果成功并且head的状态不等于0就唤醒后面等待的节点
*/
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
protected final boolean tryRelease(int releases) {
            // 释放后c的状态值
            int c = getState() - releases;
           // 如果持有锁的线程不是当前线程,直接抛出异常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
               // 如果c==0,说明所有持有锁都释放完了,其他线程可以请求获取锁
                free = true;
                setExclusiveOwnerThread(null);
            }
           // 这里只会有一个线程执行到这,不存在竞争,因此不需要CAS
            setState(c);
            return free;
        }

 

以上是关于concurrent互斥锁ReentrantLock & 源码分析的主要内容,如果未能解决你的问题,请参考以下文章

[转帖]B4. Concurrent JVM 锁机制(synchronized)

十读写锁

Linux 同步方法剖析--内核原子,自旋锁和互斥锁

深入浅出 Java Concurrency (13): 锁机制 part 8 读写锁 (ReentrantReadWriteLock)

java.util.concurrent.locks包中的ReentrantLock之非公平策略解析

reentrantlock与synchronized的区别.及Atomics的使用