手动实现一个可重入锁

package com.roocon.thread.ta1;

public class Sequence {

    private MyLock lock = new MyLock();

    private int value;

    public int getNext() {
        lock.lock();
        value++;
        lock.unlock();
        return value;

    }

    public static void main(String[] args) {

        Sequence s = new Sequence();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while(true)
                    System.out.println(s.getNext());
            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                while(true)
                    System.out.println(s.getNext());
            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                while(true)
                    System.out.println(s.getNext());
            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                while(true)
                    System.out.println(s.getNext());
            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                while(true)
                    System.out.println(s.getNext());
            }
        }).start();
    }

}

package com.roocon.thread.ta1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class MyLock implements Lock {

    private boolean isLocked = false;

    @Override
    public synchronized void lock() {
       
        while (isLocked) {//如果不是第一个进来的线程,就需要等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLocked = true;//第一个进来的线程获得锁,不需要等待

    }

    @Override
    public synchronized void unlock() {
        isLocked = false;
        notify();//wait notify 必须和synchronized一起使用
    }


    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}
 

运行结果:

1
2
3
4
5
6
7
...

现在来模拟下,基于以上代码,锁是否可重入:

package com.roocon.thread.ta1;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo {
    MyLock lock = new MyLock();

    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(); //输出a,并且一直处于等待状态,程序并未运行结束
            }
        }).start();
    }
}

分析以上运行结果:

线程1调用a方法,第一次进入lock方法,去获取锁。此时,isLocked为false,于是将标志锁改为true。然后,输出a。再去执行b方法。此时,再次去调用lock方法。lock方法是使用

synchronized修饰的,是可重入的,于是继续执行b方法中的代码。判断isLocked,由于之前进入拿到了锁,因此isLocked为true,于是,会一直等待等待。这就是为什么输出a一直等待的原因。

为了实现可重入锁的效果,改进代码如下:

package com.roocon.thread.ta1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class MyLock implements Lock {

    private boolean isLocked = false;
    private Thread lockBy = null;
    private int lockCount = 0;

    @Override
    public synchronized void lock() {
        if (isLocked && lockBy != Thread.currentThread()) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLocked = true;
        lockBy = Thread.currentThread();
        lockCount++;

    }

    @Override
    public synchronized void unlock() {
        if (lockBy == Thread.currentThread()) {
            lockCount--;
            if (lockCount == 0) {
                isLocked = false;
                notify();//wait notify 必须和synchronized一起使用
            }
        }

    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}

运行结果:

a
b

解释以上运行结果:

线程1调用a方法,执行lock方法。线程1第一次进入,获得锁,于是,将isLocked设置为true,且lockBy为当前线程Thread1,同时,lockCount=1。

输出a后,再次执行代码调用b方法,synchronized可重入,再次调用b方法中的lock。此时,isLocked为true,但是,只有lockBy和当前线程相等,不满足wait操作条件,因此,

它会再次执行后面的代码,于是,lockCount=2。然后,在输出b之后,它会执行b方法中的unlock,解锁,但是,要明确,只有当线程1将它所有的锁都释放完毕后,才会去通知那些wait等待的线程。因此,需要加入对lockCount的判断,只有lockCount为0时,才将isLock的标志位改为false,同时通知其他线程可以去获取锁了。

原文地址:https://www.cnblogs.com/sunnyDream/p/8192699.html