手写锁(二)-CAS实现可重入锁

介绍

上一篇文章我们分析了简单锁的缺点,发现简单锁竟然自己可以把自己死锁.所以可重入锁出现了,可重入锁就是为了解决自己和自己死锁的问题.锁的内部可以记住哪个线程持有锁.这样保证已经获得锁的线程不会再次获得锁

实现

我们的实现可以根据简单锁改进.

版本1

public class CustomReentrantLock1 {
    AtomicInteger atomicInteger = new AtomicInteger();
    volatile Thread curThread;

    public void lock() {
        while (!atomicInteger.compareAndSet(0, 1)) {
            if (curThread == Thread.currentThread()) break;
        }
        curThread = Thread.currentThread();
    }

    public void unLock() {
        curThread = null;
        atomicInteger.set(0);
    }

    static CustomReentrantLock1 lock = new CustomReentrantLock1();

    public static void main(String[] args) {
        lock.lock();
        methodA();
        lock.unLock();
    }

    private static void methodA() {
        lock.lock();
        //do something
        lock.unLock();
    }
复制代码

以上实现是否可行?
我们仔细观察,运行,发现好像不行.代码中的例子中,调用了两次lock.lock();,而只调用一次 lock.unLock();发现就把锁了两次的lock给释放了.所以上面的实现是不正确的.我们需要有一个变量来记录一个线程调用了多少次lock.lock

版本2

在版本1之上改进:

import java.util.concurrent.atomic.AtomicInteger;

public class CustomReentrantLock2 {
    AtomicInteger atomicInteger = new AtomicInteger();
    volatile Thread curThread;
    volatile int count;

    public void lock() {
        while (!atomicInteger.compareAndSet(0, 1)) {
            if (curThread == Thread.currentThread()) {
                count += 1;
                return;
            }
            Thread.onSpinWait();//让出cpu,但是还在竞争队列里
        }
        curThread = Thread.currentThread();
        count = 1;
    }

    public void unLock() {
        if (curThread != Thread.currentThread()) return;
        count -= 1;
        if (count == 0) {
            curThread = null;
            atomicInteger.set(0);
        }
    }

    static CustomReentrantLock2 lock = new CustomReentrantLock2();

    public static void main(String[] args) {
        lock.lock();
        methodA();
        lock.unLock();
    }

    private static void methodA() {
        lock.lock();
        //do something
        lock.unLock();
    }
}
复制代码

加了一个被 volatile修饰的count,这时我们的可重入锁好像就实现了.

扩展

问:我们是否还有其他的方式来实现可重入锁?是否可以用ThreadLocal来记录这些东西?是否可以使用ThreadLocal实现一个可重入锁?

答:可以

下篇文章介绍公平锁

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享