09、可重入锁原理、自己实现一个可重入锁

一、可重入锁原理?

可重入锁最重要的作用就是可以避免死锁。防止出现线程被自己所阻塞的情况。

比如:线程A获取了对象B的锁,开始执行代码,然后又发现下面的一个方法需要再次获取对象B的锁,此时对象B的锁已经被线程A占用了。

  • 不过只要另外一个线程和线程A来自同一个线程,那么该线程也能获取对象B的锁。
  • 目前JAVA中几乎所有的锁都是可重入锁。比如:ReentrantLock、ReentranReadWriteLock。

ReentrantLock源码分析参考博文:https://blog.csdn.net/Saintmm/article/details/124346628
ReentranReadWriteLock源码分析参考博文:[https://blog.csdn.net/Saintmm/article/details/124347762][https_blog.csdn.net_Saintmm_article_details_124347762]

可重入锁它是一个概念,在大部分时候可重入锁并不直接表示ReentrantLock,而是强调一种锁的类型。

  • Synchronized也是可重入锁、非公平锁。
  • 自旋锁也是可重入锁。(自旋锁由于第一次unlock()操作没有释放锁出现死锁时不叫可重入锁)

实现原理?

每一个锁对象都会关联的一个线程持有者和计数器。

  • 计数器为0的时候表示锁没有被获取;
  • 当用一个线程获取锁时,计数器为1,锁的线程持有者为当前线程;
  • 当前再次获取锁的时候计数器+1;
  • 解锁时计数器-1;计数器为0时,表示锁被释放了。

二、手写一个可重入锁

可重入锁可以避免死锁:

  • 一个主线程中包含两个同步方法,线程可以多次执行这两个方法
public class ReentrantLockTest1 implements Lock {

    //锁标志
    private boolean isLocked = false;
    //定义同一线程获取锁的次数
    int lockCount = 0;
    //定义一个线程
    Thread thread = null;

    @Override
    public synchronized void lock() {

        Thread currentThread = Thread.currentThread();
        //如果不是第一个进来,则等待
        while(isLocked && currentThread != thread){

            try {

                wait();
            }catch (InterruptedException e){

                e.printStackTrace();
            }
        }
        //如果是第一个进来,将锁标志设为true即该线程拥有锁。
        isLocked = true;
        //将thread指向当前线程
        thread = currentThread;
        //计数器自增
        lockCount++;
    }

    @Override
    public synchronized void unlock() {

        //如果当前线程是thread
        if(thread == Thread.currentThread()){

            lockCount--;
            if(lockCount == 0){

                notify();
                //释放锁
                isLocked = false;
            }
        }
    }
}