java-并发-源码-ReentrantLock

一. lock方法

ReentrantLock是一种排他锁
共享锁:就是允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有。
排它锁:也称作独占锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁。

定义了两种sync
NonfairSync
FairSync

AbstractQueuedSynchronizer不同意看懂,需要看子类
ReentrantLock中具有FairSync和NonfairSync,下面看下NonfairSync

二. lock方法

AbstractQueuedSynchronizer内存维护一个unsage,尝试通过CAS修改状态修其状态

    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

修改不成功会调用acquire(1),然后调用

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

tryAcquire会调用sync的nonfairTryAcquire方法
NonfairSync中对tryAcquire覆盖,方法如下

 	protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }

再次判断state是否为0,如果为0,尝试第二次,如果非0,并且属于当前线程,state+1

    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;
    }

addWaiter方法,传入EXCLUSIVE类型

 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)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

第一次tail为空,创建一个新节点,头和尾都为这个节点,然后把node加入后面,形成双向链表,如果线程很多,那么会形成一条比较长的链表;

   final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

shouldParkAfterFailedAcquire方法会从倒数第二个节点到头,设置node状态为SIGNAL
parkAndCheckInterrupt把所有的线程阻塞在倒数第二个结点
一个结点休眠一个线程

三. unlock方法

   public void unlock() {
        sync.release(1);
    }

调用AQS的release方法调用tryRelease解锁
如果完全释放,开启第一个阻塞的线程,即头部

  public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease方法,如果其他线程解锁会抛异常,解锁后占用的state-1
如果完全释放,返回ture

    protected final 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;
    }

## 四. 例子
public class AttemptLocking {
    private ReentrantLock lock = new ReentrantLock();

    public void untimed() {
        boolean captured = lock.tryLock();
        try {
            System.out.println("tryLock(): " + captured);
        } finally {
            if (captured)
                lock.unlock();
        }
    }

    public void timed() {
        boolean captured = false;
        try {
            captured = lock.tryLock(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        try {
            System.out.println("tryLock(2, TimeUnit.SECONDS): " + captured);
        } finally {
            if (captured)
                lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final AttemptLocking al = new AttemptLocking();
        al.untimed(); // True -- 可以成功获得锁
        al.timed(); // True --可以成功获得锁
        //新创建一个线程获得锁并且不释放
        new Thread() {
            {
                setDaemon(true);
            }

            public void run() {
                al.lock.lock();
                System.out.println("acquired");
            }
        }.start();
        Thread.sleep(100);// 保证新线程能够先执行
        al.untimed(); // False -- 马上中断放弃
        al.timed(); // False -- 等两秒超时后中断放弃
    }
}
posted @ 2016-09-12 19:24  zhangshihai1232  阅读(93)  评论(0)    收藏  举报