6.23Java多线程可重入锁实现原理

Posted 俊king

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6.23Java多线程可重入锁实现原理相关的知识,希望对你有一定的参考价值。

6.23Java多线程可重入锁实现原理

什么是可重入锁?

  • 某个线程试图获取一个已经由它自己持有的锁时,这个请求会立刻成功

  • 将这个锁的计数值+1.同时锁住资源

  • 当线程退出同步代码块时,计数器将会递减。计数值=0时,锁释放

如果没有可重入锁,第二次获得锁时会进入死锁状态

锁是作为并发共享数据,保证一致性的工具

之前用的锁是内置锁,内部已经设置好了。

可重入锁代码示例

package thread.rearrangement;

/**
* 可重入锁,锁可以延续使用
* @since JDk 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class LockTest {

   public void test(){

       /**
        * 第一次获得锁
        */
       synchronized(this){
           while(true){
               /*第二次获得同样的锁*/
               synchronized(this){
                   System.out.println("ReentrantLock!");
              }

               try{
                   Thread.sleep(1000);
              }catch(InterruptedException e){
                   e.printStackTrace();
              }
          }
      }

  }

   public static void main(String[] args) {
       new LockTest().test();
  }
}

使用同步方法

class ReentrantLockTest{
   public synchronized void a(){
       
  }
   
   public synchronized void b(){
       
  }
   
   /**
   * 可重入锁的用法
   */
   public synchronized void all(){
       this.a();
       this.b();
  }
}
不可重入锁代码示例
package thread.rearrangement;

/**
* 不可重入锁:表示锁不可以延续使用--->循环
* @since JDK 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class LockTestNo2 {

   /*使用锁*/
   Lock lock = new Lock();

   /*成员方法*/
   public void a() throws InterruptedException {
       lock.lock();
       doSomething();
       lock.unlock();
  }

   /*不可重入--->属性值不能往下面带,用了锁之后不会释放掉*/
   public void doSomething() throws InterruptedException {
       lock.lock();
       //......
       lock.unlock();
  }

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

       LockTestNo2 testNo2 = new LockTestNo2();
       testNo2.a();
       testNo2.doSomething();
  }

}

/**
* 自定义锁的类:这是一个不可重入锁
*/
class Lock{

   /*表示是否被占用的属性*/
   private boolean isLocked = false;

   /*使用锁的方法*/
   public synchronized void lock() throws InterruptedException {
       /*写一个死循环*/
       while (isLocked){
           /*加入等待线程*/
           wait();
      }

       /*锁的状态改变*/
       isLocked = true;

  }

   /*释放锁的方法*/
   public synchronized void unlock(){

       /*属性变为初始化*/
       isLocked = false;

       /*唤醒资源*/
       notifyAll();

  }

}
可重入锁demo

实现原理:当线程请求锁时先判断进来的线程是否是当前已持有锁的线程,如果是就直接使用。如果不是就等待

package thread.rearrangement;

/**
* 可重入锁,锁可以延续使用
* 锁可以延续使用,每一个锁都有一个计数器
* @since JDk 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class LockTestNo3 {

   /*使用锁*/
   ReLock reLock = new ReLock();

   /*成员方法*/
   public void a() throws InterruptedException {
       reLock.lock();
       System.out.println(reLock.getHoldCount());
       doSomething();
       reLock.unlock();
       System.out.println(reLock.getHoldCount());
  }

   /*不可重入--->属性值不能往下面带,用了锁之后不会释放掉*/
   public void doSomething() throws InterruptedException {
       reLock.lock();
       System.out.println(reLock.getHoldCount());
       //......
       reLock.unlock();
       System.out.println(reLock.getHoldCount());
  }

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

       LockTestNo3 testNo3 = new LockTestNo3();
       testNo3.a();

       Thread.sleep(1000);

       /*查看计数器*/
       System.out.println(testNo3.reLock.getHoldCount());
  }

}

/**
* 自定义锁的类:这是一个不可重入锁
*/
class ReLock{

   /*表示是否被占用的属性*/
   private boolean isLocked = false;

   /*加入一个存储线程*/
   private Thread lockedBy = null;

   /*加入一个计数器,统计锁的使用*/
   private int holdCount = 0;

   /*使用锁的方法*/
   public synchronized void lock() throws InterruptedException {

       /*取当前线程变量*/
       Thread t = Thread.currentThread();

       /*写一个死循环*/
       while (isLocked&&lockedBy!=t){
           /*加入等待线程*/
           wait();
      }

       /*锁的状态改变*/
       isLocked = true;

       /*把t赋值给lockedBy*/
       lockedBy = t;

       /*计数器+1*/
       holdCount++;

  }

   /*释放锁的方法*/
   public synchronized void unlock(){

       /*当前线程=自身的时候释放锁*/
       if (Thread.currentThread()==lockedBy){

           /*计数器自减少*/
           holdCount--;

           /*计数器为0时候释放锁*/
           if (holdCount==0){

               /*改变锁状态*/
               isLocked = false;

               /*唤醒资源*/
               notify();

               /*重置线程*/
               lockedBy = null;

          }
      }

       /*属性变为初始化*/
       isLocked = false;

       /*唤醒资源*/
       notifyAll();

  }


   /*提供get方法*/
   public int getHoldCount() {
       return holdCount;
  }
}

JUC包下的ReentrantLock类实现了可重入锁的操作

 

以上是关于6.23Java多线程可重入锁实现原理的主要内容,如果未能解决你的问题,请参考以下文章

ReentrantLock实现原理-何为可重入

ReentrantLock可重入锁在我们的代码中。

Java并发-- ReentrantLock 可重入锁实现原理2 - 释放锁

多线程之synchronoized实现可重入锁

Java并发包4--可重入锁ReentrantLock的实现原理

java 多线程-可重入锁