6.手把手教你实现自己的重入锁

首先我们可以先写一个锁的测试类,来让自己的锁实现好后。可以确保有效。

public class Sequence {
    private Lock lock = new MLock();
    private int value;
    public int getNext(){
        lock.lock();
        value++;
        lock.unlock();
        return value;
    }
}

接下来我们思考,加锁是一个什么效果。第一个线程进来可以获得锁,之后进来的线程应该等待,直到第一个线程把锁释放。
那么我们首先还是需要对LOCK这个方法做SYNCHRONIZED保护。随后可以维护一个BOOLEAN来表示是否是第一个线程。其余的就调用WAIT就可以实现阻塞的效果。

private boolean isLocked = false;
    @Override
    public synchronized void lock() {
        while(isLocked){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLocked = true;
    }

那么LOCK对应的UNLOCK就应该用NOTIFY就好了。

@Override
    public synchronized void unlock() {
        isLocked = false;
        notify();
    }

在sequence里写下MAIN方法

public static void main(String[] args) {
        Sequence s = new Sequence();
        for(int i = 0; i < 5; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i = 0;i<10;i++){
                        System.out.println(s.getNext());
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }).start();
        }
    }

发现没啥问题,
我们可以把锁去掉,再看看。答案只有48了,少了2.

接下来我们来实现可以重入的锁。
先写个测试类

Lock lock = new MLock();
    public void a(){
        lock.lock();
        System.out.println("a");
        b();
        lock.unlock();
    }
    public void b(){
        lock.lock();
        System.out.println("b");
        lock.unlock();
    }

    public static void main(String[] args) {
        Demo d = new Demo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.a();
            }
        }).start();
    }

如果我们直接运行发现输出A之后就会无限期等待了。
之所以会这样,是因为同一个进程先调了2次LOCK,再第2次就卡主了。所以我们只要记住持有锁的当前线程。
lock改造如下

Thread lockBy = null;
    int lockCount = 0;
    @Override
    public synchronized void lock() {
        Thread current = Thread.currentThread();

        if(isLocked && current != lockBy){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLocked = true;
        lockBy = current;
        lockCount++;
    }

unlock 改造如下

@Override
    public synchronized void unlock() {
        if(lockBy != Thread.currentThread()){
            return;
        }
        lockCount--;
        if(lockCount == 0){
            isLocked = false;
            notify();
            lockBy = null;
        }

    }

再跑一遍原来的测试代码就可以过了。

你可能感兴趣的:(6.手把手教你实现自己的重入锁)