zoukankan      html  css  js  c++  java
  • 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类实现了可重入锁的操作

     

    It's a lonely road!!!
  • 相关阅读:
    Testlink & Redmine组合拳演练
    使用IP欺骗Loadrunner并发测试小结
    程序设计的思想与执行步骤参考
    读《世界是自己的,与他人无关》
    读《A4纸上的奇迹》
    读《流动的盛宴》
    既往不恋,当下不杂,未来不乱——读《怦然心动的人生整理魔法》
    GridCtrl学习笔记(3)一行一行地更新表格,有bug版
    GridCtrl学习笔记(2)寻找自动更新表格的最新数据并把其显示到当前窗口的方法
    GridCtrl学习笔记(1)建立使用GridCtrl的工程
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/14923081.html
Copyright © 2011-2022 走看看