彻底搞懂可重入锁和不可重入锁 && 手写可重入锁和不可重入锁

文章目录

      • 什么是可重入锁?
      • 什么是不可重入锁?
      • 手写不可重入锁
      • 手写可重入锁
      • juc包下的可重入锁

什么是可重入锁?

当某个线程试图获取一个自己已经持有的锁时,那么会立刻获得这个锁,不用等待,可以理解为这个锁可以继承。
同时这个锁的计数器也会加1,但计数器为0时,释放锁。
如果没有可重入锁,那么当已经拿到锁的线程再次获取锁时就会进入死锁状态。可重入锁是很常见的。

下面看一个简单的案例来理解可重入锁

public class ReentrantTest {

    public static void main(String[] args) {
        // 第一次获取锁
        synchronized (ReentrantTest.class){
            while (true){
//            第二次获取锁
                synchronized (ReentrantTest.class){
                    System.out.println("ReentrantLock");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

结果如下:
彻底搞懂可重入锁和不可重入锁 && 手写可重入锁和不可重入锁_第1张图片
发现同一个线程可以多次获取这个锁,即当一个线程获取了某个锁后,当这个线程再次获取这个锁时,就会默认已经获取了。

什么是不可重入锁?

即一个线程获取一个到一个锁之后,当这个线程再次获取这个锁,需要等待这个线程释放锁之后才能获取,这很明显就是阻塞了嘛~~

手写不可重入锁

实现起来其实也挺简单的,代码如下

/**
 * @author wcong
 * @version 1.0
 * @date 2020-08-06 19:09
 */
 class NotReentrantLock{

    private static boolean isLock = false;

    // 加锁
    public synchronized void lock() throws InterruptedException {
//        判断是否加锁
        while (isLock){
            wait();
        }
//        锁住当前线程
        isLock = true;
    }

    // 解锁
    public synchronized void unLock(){
        isLock = false;
        notify();
    }
}
public class 手写不可重入锁 {
    private static NotReentrantLock notReentrantLock = new NotReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        test();
    }
    public static void test() throws InterruptedException {
        notReentrantLock.lock();
        dosomething();
        notReentrantLock.unLock();
    }

    public static void dosomething() throws InterruptedException {
        notReentrantLock.lock();
        System.out.println("dosomething...");
        notReentrantLock.unLock();
    }

}

结果会被阻塞
彻底搞懂可重入锁和不可重入锁 && 手写可重入锁和不可重入锁_第2张图片

手写可重入锁

package com.wcong.thread;

/**
 * 手写可重入锁的实现
 * @author wcong
 * @version 1.0
 * @date 2020-08-06 19:09
 */

class MyReentrantLock{

    // 判断是否加锁
    private boolean isLock = false;
    // 锁计数器,记录锁的个数
    private int count;
    //    判断是否在同一个线程中
    private Thread thread;

    // 加锁
    public synchronized void lock() throws InterruptedException {
        Thread tep = Thread.currentThread();
//        如果在一个线程内则不锁定线程,即可重入
        while (isLock && thread!=tep){
            wait();
        }
//        锁住当前线程
        count++;
        isLock = true;
        thread = tep;
    }

    // 解锁
    public synchronized void unLock(){
        isLock = false;
        thread = null;
        notify();
        count--;
    }

    // get set...
    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}
public class 手写可重入锁 {

    private static MyReentrantLock myReentrantLock = new MyReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        test();
    }

    /**
     * 测试方法
     * @throws InterruptedException
     */
    public static void test() throws InterruptedException {
        myReentrantLock.lock();
        System.out.println(myReentrantLock.getCount());
        dosomething();
        myReentrantLock.unLock();
        System.out.println(myReentrantLock.getCount());
    }

    public static void dosomething() throws InterruptedException {
        myReentrantLock.lock();
        System.out.println(myReentrantLock.getCount());
        System.out.println("dosomething...");
        myReentrantLock.unLock();
        System.out.println(myReentrantLock.getCount());
    }

}


代码执行结果如下
彻底搞懂可重入锁和不可重入锁 && 手写可重入锁和不可重入锁_第3张图片

juc包下的可重入锁

juc包有实现可重入锁,其原理和上面的差不多,性能肯定比手写的要好,下面只是简单的使用一下。

/**
 * juc包下的可重入锁
 * @author wcong
 * @version 1.0
 * @date 2020-08-06 21:54
 */
public class JucReentrantTest {

    private static ReentrantLock reentrantLock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        test();
    }

    /**
     * 测试方法
     * @throws InterruptedException
     */
    public static void test() throws InterruptedException {
        reentrantLock.lock();
        System.out.println(reentrantLock.getHoldCount());
        dosomething();
        reentrantLock.unlock();
        System.out.println(reentrantLock.getHoldCount());
    }

    public static void dosomething() throws InterruptedException {
        reentrantLock.lock();
        System.out.println(reentrantLock.getHoldCount());
        System.out.println("dosomething...");
        reentrantLock.unlock();
        System.out.println(reentrantLock.getHoldCount());
    }

}

执行结果如下:
彻底搞懂可重入锁和不可重入锁 && 手写可重入锁和不可重入锁_第4张图片

你可能感兴趣的:(java并发编程)