当前位置: 首页 > article >正文

Java锁 可重入锁(递归锁) 深入源码解析 ReentrantLock synchronized

目录

解释

可重入锁 详细解释

样例 1

样例 2 多层结构

Synchronized 的重入性的实现原理

ReentrantLock 必须支持可重入锁

BUG 写法


解释

可重入锁又叫递归锁

不会因为之前已经获取过还没释放而阻塞

可重入锁又名递归锁

是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提,锁对象得是同一个对象),不会因为之前已经获取过还

没释放而阻塞。

如果是1个有 synchronized 修饰的递归调用方法,

程序第2次进入被自己阻塞了岂不是天大的笑话,出现了作茧自缚。

所以Java中ReentrantLock和synchronized都是可重入锁,可重入锁的一个优点是可一定程度避免死锁。

可重入锁 详细解释

一个线程中的多个流程可以获取同一把锁

持有这把同步锁可以再次进入

自己可以获取自己的内部锁

简单的来说就是:在一个synchronized修饰的方法或代码块的内部调用本类的其他synchronized修饰的方法或代码块时,是永远可以得到锁的
 

样例 1

外层

public class ReEntryLockDemo {
    static Object objectLock=new Object();
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (objectLock){
                System.out.println("----外层");
            }
        },"t1").start();
    }
}

样例 2 多层结构

public class ReEntryLockDemo {
    static Object objectLock=new Object();
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (objectLock){
                System.out.println("----外层");
                synchronized (objectLock){
                    System.out.println("----中层");
                    synchronized (objectLock){
                        System.out.println("----内层");
                    }
                }
            }
        },"t1").start();
    }
}

这样 方法栈会爆

StackOverflowError

可重入锁是一种机制

预防死锁


Synchronized 的重入性的实现原理

每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针。

当执行monitorenier时,如果目标锁对象的计数器为零,那么说明它没有被其他线程所持有,Java虚拟机会将该锁对象的持有线程设置为当前线程,并且将其计数器加1。

在目标锁对象的计数器不为零的情况下,如果锁对象的持有线程是当前线程,那么 Java 虚拟机可以将其计数器加1,否则需要等待

直至持有线程释放该锁。

当执行monitorexit时,Java虚拟机则需将锁对象的计数器减1。计数器为零代表锁已被释放。

ReentrantLock 必须支持可重入锁

标准写法

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReEntryLockDemo {
    static Object objectLock=new Object();
    // 支持递归
    public synchronized void  m1(){
        m1();
    }
    public static void main(String[] args) {
//        new Thread(() -> {
//            synchronized (objectLock){
//                System.out.println("----外层");
//                synchronized (objectLock){
//                    System.out.println("----中层");
//                    synchronized (objectLock){
//                        System.out.println("----内层");
//                    }
//                }
//            }
//        },"t1").start();
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        new Thread(() ->{
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName()+"\t"+"---外层");
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName()+"\t"+"---内层");
                    lock.lock();
                }finally {
                    lock.unlock();
                }
            }finally {
                lock.unlock();
            }
        },"t1").start();
    }
}

BUG 写法

但是不会报错

但是如果第二个线程要去拿 lock 这把锁

是拿不到的

这个线程就不能获得锁

上锁两次 下锁两次


http://www.kler.cn/a/510930.html

相关文章:

  • 大模型GUI系列论文阅读 DAY1:《基于大型语言模型的图形用户界面智能体:综述》
  • AI时代下 | 通义灵码冲刺备战求职季
  • 【前端】CSS学习笔记
  • Java 接口安全指南
  • 数组常见解决方案
  • R语言的并发编程
  • Linux TFTP 使用
  • 第38天:Web开发-JS应用NodeJS原型链污染文件系统Express模块数据库通讯审计
  • C语言之文本加密程序设计
  • Three.js贴图加载与环境遮蔽贴图强度设置(五)
  • 【Java回顾】Day7 Java IO|分类(传输方式,数据操作)|零拷贝和NIO
  • Linux 创建用户
  • 数据结构——链表和单向链表
  • 02内存结构篇(D2_剖析运行数据区)
  • Java——Stream流的peek方法详解
  • 【opencv】第9章 直方图与匹配
  • 基于.Net Core+Vue的文件加密系统
  • MySQL 可视化工具
  • 31、【OS】【Nuttx】OSTest分析(1):stdio测试(一)
  • MySQL程序之:使用类似URI的字符串或键值对连接到服务器
  • ubuntu24.0安装JDK8-281版本
  • 【游戏设计原理】71 - 兴趣曲线
  • AIGC视频生成明星——Emu Video模型
  • 【AI | pytorch】torch.view_as_complex的使用
  • 线性代数概述
  • 基于 Spring Cloud 、Spring Boot、 OAuth2 的 RBAC 企业快速开发平台