Fork me on GitHub

可重入锁与不可重入锁

可重入锁(递归锁)

定义:可以递归调用的锁(当某个线程执行某个方法已经获得该锁,在方法中可以再次获取该锁,并且不会发生死锁(前提时同一个对象或Class))
可重入:某个线程已经获得了某个锁,可以再次获取锁而不会出现死锁。

注意:synchronized和ReentrantLock都时可重入锁。

不可重入锁

定义:不可以递归调用的锁(当某个线程执行某个方法已经获得该锁,在方法中再次获取该锁时,会发生阻塞)

自定义可重入锁

解释:当一个类中有A,B两个方法都要加锁,A方法中要调用B方法。当线程1执行A方法时会同时获取A,B两把所锁,只有线程1执行完A方法并释放掉这两把锁时,其他线程才能获得锁。

package juc.lock.Reentrant;

//自定义可重入锁
public class Lock {
    private boolean isLock = false;//判断当前锁状态,
    private Thread currentThread = null;//当前线程
    private int lockCount = 0;//当前锁的层数
    //加锁方法
    public synchronized void lock(){
        while (isLock && currentThread != Thread.currentThread()){//当第二次加锁时,第二个条件为false
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLock = true;
        currentThread = Thread.currentThread();
        lockCount++;
    }
    //解锁方法
    public synchronized void unlock(){
        if (isLock && currentThread == Thread.currentThread()){
            if (--lockCount==0){
                isLock=false;
                notify();
            }
        }
    }
}
class Test{

    Lock lock = new Lock();//自定义可重入锁

    public static void main(String[] args) {
        Test test = new Test();

        new Thread(()->{
            test.eat();
        },"A").start();

        new Thread(()->{
            test.drink();
        },"B").start();
    }
    public void eat(){
        try {
            lock.lock();
            System.out.println("线程"+Thread.currentThread().getName()+"->eat");
            Thread.sleep(1000);
            drink();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
    public void drink(){
        try {
            lock.lock();
            System.out.println("线程"+Thread.currentThread().getName()+"->drink");
        }finally {
            lock.unlock();
        }
    }
}

运行结果:

自定义不可重入锁

解释:当一个类中有多个方法,且这些方法都需要获得并释放锁。但其中的某个方法得到锁之后,其他方法必须等该方法释放锁之后才能有获得锁的机会。

package juc.lock.nonReentrant;

//自定义不可重入锁
public class Lock {
    private boolean isLock = false;//判断当前锁状态
    public synchronized void lock(){
        while (isLock){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
		isLock = true;
    }
    public synchronized void unlock(){
        if (isLock){
            isLock = false;
            notify();
        }
    }
}
class Test{
    private Lock lock = new Lock();//自定义不可重入锁

    public static void main(String[] args) {
        Test test=new Test();
        new Thread(()->{
            test.eat();
        },"A").start();

        new Thread(()->{
            test.drink();
        },"B").start();
    }
    public void eat(){
        try {
            lock.lock();
            System.out.println("线程"+Thread.currentThread().getName()+"->eat");

            Thread.sleep(1000);

            drink();//调用drink方法尝试再次获取锁时,由于已经加过锁了,所以isLock为true,因此会一直wait。
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void drink(){
        try {
            lock.lock();
            System.out.println("线程"+Thread.currentThread().getName()+"->drink");
        } finally {
            lock.unlock();
        }
    }
}

运行结果:

posted @ 2021-01-24 16:08  雾深  阅读(654)  评论(0编辑  收藏  举报