可重入锁

Posted by Clear Blog on June 10, 2017

可重入锁,也叫做递归锁, 指的是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。 在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁。 我们自己来实现一个可重入锁,可以更加透彻的理解可重入的概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
* @author xuguangwu 
*/
public class MyLock implements Lock {

    private Sync sync = new Sync();

    public void lock() {
//        sync.tryAcquire(1);
        sync.acquire(1);
    }

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

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

    public Condition newCondition() {
        return sync.newConditionObj();
    }

    private class Sync extends AbstractQueuedSynchronizer {


        @Override
        protected boolean tryAcquire(int arg) {
            int state = getState();
            if (state == 0) {
                for (; ; ) {
                    if (compareAndSetState(0, arg)) {
                        //设置当前线程占用资源
                        setExclusiveOwnerThread(Thread.currentThread());
                        return true;
                    }
                    //这里为重入的实现
                    if (getExclusiveOwnerThread().equals(Thread.currentThread())) {
                        setState(state + arg);
                        return true;
                    }
                }
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            int state = getState() - arg;
            boolean flag = false;
            if (state == 0) {
                setExclusiveOwnerThread(null);
                setState(state);
                return true;
            }
            /**
             * 不存在线程安全问题,在释放前已经独占了state,重入性问题
             */
            setState(state);
            return false;
        }

        public Condition newConditionObj() {
            return new ConditionObject();
        }

        /**
         * 共享
         *
         * @param arg
         * @return
         */
        @Override
        protected int tryAcquireShared(int arg) {
            return super.tryAcquireShared(arg);
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            return super.tryReleaseShared(arg);
        }
    }
}

将核心代码圈出来

1
2
3
4
if (getExclusiveOwnerThread().equals(Thread.currentThread())) {
    setState(state + arg);
    return true;
}

再结合一个实际调用的案例来理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.concurrent.locks.ReentrantLock;

public class Demo {
        MyLock myLock = new MyLock();
//    ReentrantLock myLock = new ReentrantLock();

    public void a() {
        myLock.lock();
        System.out.println("a");
        b();
        myLock.unlock();
    }

    public void b() {
        myLock.lock();
        System.out.println("b");
        myLock.unlock();
    }

    public static void main(String[] args) {
        Demo demo = new Demo();
        new Thread(() -> demo.a()).start();
    }
}

新建一个线程,调用方法a(),a()中调用方法b(),两个方法都会去获取同一把锁,如果没有可重入机制, 那么就会发生死锁。ok,以上就是我对可重入锁的理解。