小工具      在线工具  汉语词典  css  js  c++  java

Java可重入锁与不可重入锁

Java 额外说明

收录于:43天前

所谓可重入锁,就是指线程单元。一个线程获取对象锁后,该线程可以再次获取该对象的锁,但其他线程则不能。

synchronized 和 ReentrantLock 都是可重入锁。

可重入锁的目的是防止死锁。

实现原理是通过为每个锁关联一个请求计数器和一个占有它的线程。当计数为0时,认为锁是未被占有的;线程请求一个未被占有的锁时,JVM将记录锁的占有者,并且将请求计数器置为1 。

如果同一个线程再次请求锁,则计数会递增;

每次占用线程退出同步块时,计数器值都会递减。直到计数器达到 0 时,锁才被释放。

关于父类和子类的锁的重入:子类重写父类的同步方法,然后调用父类中的方法。如果此时没有可重入锁,那么这段代码就会产生死锁(很可能很容易理解)。

例子:

比如A类中有一个方法:public synchronized methodA1(){

方法A2();

}

和公共同步方法A2(){

//详细操作

}

也是A类中的一种同步方法,当当前线程调用A类的对象methodA1同步方法时,如果其他线程没有获得A类的对象锁,那么当前线程就获得当前A类对象的锁,然后执行methodA1同步方法。当body中调用methodA2同步方法时,当前线程可以再次获取A类对象的锁,但其他线程则不能。这是一个可重入锁。

代码演示:

不可重入锁:

public class Count{
    Lock lock = new Lock();
    public void print(){
        lock.lock();
        doAdd();
        lock.unlock();
    }
    public void doAdd(){
        lock.lock();
        //do something
        lock.unlock();
    }
}

要使用此锁:

public class Count{
    Lock lock = new Lock();
    public void print(){
        lock.lock();
        doAdd();
        lock.unlock();
    }
    public void doAdd(){
        lock.lock();
        //do something
        lock.unlock();
    }
}

当前线程执行print()方法时,首先获取锁。那么,当执行doAdd()方法时,doAdd()中的逻辑就无法执行,必须先释放锁。这个例子是不可重入锁定的一个很好的例子。

可重入锁:

接下来我们设计一个可重入锁

public class Lock{
    boolean isLocked = false;
    Thread  lockedBy = null;
    int lockedCount = 0;
    public synchronized void lock()
            throws InterruptedException{
        Thread thread = Thread.currentThread();
        while(isLocked && lockedBy != thread){
            wait();
        }
        isLocked = true;
        lockedCount++;
        lockedBy = thread;
    }
    public synchronized void unlock(){
        if(Thread.currentThread() == this.lockedBy){
            lockedCount--;
            if(lockedCount == 0){
                isLocked = false;
                notify();
            }
        }
    }
}

所谓可重入,是指线程可以进入它已经拥有的锁的同步代码块。

我们设计两个线程来调用 print() 方法。第一个线程调用print()方法获取锁,并进入lock()方法。由于初始lockedBy为null,因此不会进入while并挂起当前线程,而是会递增当前线程。测量第一个线程的lockedCount并记录lockBy。然后第一个线程进入doAdd()方法。既然是同一个进程,就不会进入while而hang。然后它增加lockedCount。当第二个线程尝试加锁时,它不会获取锁,因为isLocked=true。直到第一个线程调用unlock()两次将lockCount减至0之前,标志isLocked不会设置为false。

可重入锁的概念和设计思想大体是相同的,Java中的可重入锁ReentrantLock的设计思想也是相同的。

Synchronized 和 ReentrantLock 都是可重入锁。

ReentrantLock和synchronized的比较:

1.前者使用灵活,但必须手动打开和释放锁

2、前者扩展性好,有时间锁等待(tryLock())、可中断锁等待(lockInterruptically())、锁投票等,适合锁竞争高、条件变量多的地方。

3、前者提供了可轮询的锁请求,可以尝试获取锁(tryLock())。如果失败,则释放所获取的锁。有完善的错误恢复机制,避免死锁。

转自:https://blog.csdn.net/qq_39101581/article/details/82144499?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-7.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu- 7.无案例

. . .

相关推荐

额外说明

leetcode47(全排列二:回溯+哈希去重)

给定一个可包含重复数字的序列,返回所有不重复的全排列。 示例: 输入: [1,1,2] 输出: [ [1,1,2], [1,2,1], [2,1,1] ] 题解:这是一道枚举+组合的题目,可以用回溯法得到所有的组合情况,只不过序列中存在重复数字,我们需要

额外说明

SpringBoot整合mybatisplus和druid

文章目录 版本介绍 环境准备 导入依赖 application.yml配置 数据库表 使用 MybatisPlusConfig User UserMapper UserService UserBaseVO UserUpdateReqVO UserCrea

额外说明

Active MQ 初探(一)

Active MQ (一) Active MQ是Apache一个开源的消息中间件,也可以理解为其是一个消息总线,ActiveMQ是一个完全支持JMS1.1规范和J2EE1.4规范的JMS的Provider的实现,其需要有Java环境,且是一个面向Java

额外说明

男人来自火星,女人来自金星(摘要)

本文摘录自原著,不完全代表本人观点,未摘录文中的案例分析,建议阅读原著,会有更深刻的体会。 本文地址:http://blog.csdn.net/csqingchen/article/details/51589190 第一章 男人和女人来自不同的星球 每一

额外说明

[C语言]运用函数指针数组构建一个简单计算器

                1.函数指针数组                 函数指针数组,即为存放函数首地址的数组,类型为函数指针类型。                      2.运用函数指针数组构建简单计算器                

额外说明

大数据学习笔记:创建与配置虚拟机[Ubuntu + CentOS]

文章目录 一、创建虚拟机 (一)创建四个虚拟机 (二)查看网络拓扑结构 二、配置虚拟机 (一)配置ubuntu虚拟机 (二)配置master虚拟机 (三)配置slave1虚拟机 (四)配置slave2虚拟机 三、本地远程桌面连接ubuntu虚拟机 (一)

额外说明

yolov1代码中的coor_mask.unsqueeze(-1) & coor_mask.expand_as(tensor)

import torch tensor = torch.randn(1,7,7,30) print(tensor) print(tensor.shape) torch.Size([1, 7, 7, 30]) coor_mask = tensor[:,

额外说明

三、请求与响应

三、请求与响应 3.1、请求数据 (1)获取基本请求数据 r.GET("/test", func(c *gin.Context) { // 获取基本请求信息 fmt.Println(c.Request.Method) // 获取请求方法,输出

额外说明

ZooKeeper【部署 02】apache-zookeeper-3.6.0 集群版(准备+安装配置+启动验证)

为保证集群高可用,Zookeeper 集群的节点数最好是奇数,最少有三个节点,所以这里演示搭建一个三个节点的集群。这里我使用三台主机进行搭建,主机名分别为 hadoop001,hadoop002、hadoop003。 1. 前期准备 主机名与ip地址映射

ads via 小工具