java - 锁粒度

2023-11-13

最近工作有个需求,需要加锁保证操作的原子性,但在一定程度上我想着可以根据业务类型对锁进行细化,于是简单的写了一个demo进行验证。
先来看看synchronized的demo:


import java.util.concurrent.ConcurrentHashMap;

public class MapLockDemo {
    private static final ConcurrentHashMap<String, Object> lockMap = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        lockMap.put("key_1", new Object());
        new Thread(() -> {
            try {
                syncLock1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                syncLock2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    public static void syncLock1() throws InterruptedException {
        Object key1 = lockMap.get("key_1");
        System.out.println("syncLock1获取中");
        synchronized (key1) {
            System.out.println("syncLock1已获取");
            Thread.sleep(10000);
        }
        System.out.println("syncLock1已经释放");
    }

    public static void syncLock2() throws InterruptedException {
        Object key1 = lockMap.get("key_1");
        System.out.println("syncLock2获取中");
        synchronized (key1) {
            System.out.println("syncLock2已获取");
            Thread.sleep(10000);
        }
        System.out.println("syncLock2已经释放");
    }
}

结果如下:
在这里插入图片描述
那么我们就可以维护一个锁池来进行细粒度的控制:

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RepertoryService {
    // key -> lockObject
    private final ConcurrentHashMap<String, Object> lockMap = new ConcurrentHashMap<>();
    //分段减的库存
    private final Map<String, Integer> quotaMap = new HashMap<>();


    public synchronized Object getLock(String key) {
        Object lock = lockMap.get(key);
        if (lock == null) {
            Object lockObject = new Object();
            lockMap.put(key, lockObject);
            return lockObject;
        } else {
            return lock;
        }
        
    }

    public void addQuota(String key, int number) throws InterruptedException {
        Object lock = getLock(key);
        synchronized (lock) {
            Thread.sleep(100);
//            System.out.println(String.format("addQuota:{%s},key:{%s}", number, key));
            Integer quota = quotaMap.get(key);
            quota += number;
            quotaMap.put(key, quota);
            System.out.println(String.format("key -> {%s},now quota:{%s}", key, quota));
        }
    }

    public void addQuotaNoSync(String key, int number) throws InterruptedException {

        Thread.sleep(100);
//            System.out.println(String.format("addQuota:{%s},key:{%s}", number, key));
        Integer quota = quotaMap.get(key);
        quota += number;
        quotaMap.put(key, quota);
        System.out.println(String.format("key -> {%s},now quota:{%s}", key, quota));
    }

    public void subQuota(String key, int number) throws InterruptedException {
        Object lock = getLock(key);
        synchronized (lock) {
            Thread.sleep(100);
//            System.out.println(String.format("addQuota:{%s},key:{%s}", number, key));
            Integer quota = quotaMap.get(key);
            quota -= number;
            quotaMap.put(key, quota);
            System.out.println(String.format("key -> {%s},now quota:{%s}", key, quota));
        }
    }

    public static void main(String[] args) {
        RepertoryService service = new RepertoryService();
        ExecutorService pool = Executors.newFixedThreadPool(8);
        for (int i = 0; i < 100; i++) {
            service.quotaMap.put(generateKey(i), 100);
        }
        for (int i = 0; i < 100; i++) {
            int finnalI = i;
            pool.execute(() -> {
                try {
                    service.addQuotaNoSync(generateKey(finnalI), 1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        pool.shutdown();
        System.out.println(service.quotaMap.toString());
    }

    public static String generateKey(int n) {
        return "quota_" + n % 10;
    }
}

对与不同key值获取不同的锁,这个key值可有业务模型进行生成。这里采用了一个简单的object作为synchronized的锁对象。其实也可以采用java自带的一些锁来作为lockMap的value部分。但在这里为了保证获取锁的线程安全,避免相同的key在同时获取锁的时候创建了多个不一样的锁,做了一个全局的获取锁的锁来保证线程安全。

其实再优化一下及对业务量有个预估,将这些锁预先创建出来,通过对key的hash值来hash到这些预先创建的锁上。那么就不用一个全局的获取锁的锁来保证锁的创建了。

但是如今java项目基本都是微服务架构,基本等同于废弃了synchronized和自带的Lock,以上方案在分布式下并不可用

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java - 锁粒度 的相关文章

  • OSGi:将参数传递给特定包

    我有一个带有自定义 Main 类的自定义 jar 它启动 OSGi 框架并安装 启动捆绑包 这个主 jar 还包括一个属性文件 目标 我有一个包 A 它应该以某种方式获取主 jar 的该属性文件的属性 我的第一次尝试是在捆绑包 A 中定义一
  • 数组查找时间复杂度和。它是如何存储的

    众所周知 通过索引访问数组的时间复杂度是O 1 Java 的文档ArrayList 它由数组支持 对其也有同样的说法get手术 size isEmpty get set iterator 和 listIterator 操作以恒定时间运行 查
  • Spring Batch如何作为Reader读取多个表(查询)并将其写入平面文件写入

    在我的项目中 我读取了具有不同查询的多个表 并将这些结果集合并到平面文件中 我该如何实现这一目标 我的意思是 JdbcReader 直接采用 1 个选择查询 我如何自定义它 如果 JdbcCursorItemReader 不能满足您的需求
  • 定制法国号码格式

    我尝试为美国国家 地区使用自定义数字格式 到目前为止效果很好 Not something I want NumberFormat numberFormat0 NumberFormat getNumberInstance Locale US
  • JLabel.setText() 中的换行符

    使用 JLabel setText 时如何插入换行符 我尝试使用 Html 但似乎可以使其适用于 setText 仅适用于 jLabel 的初始声明 最初声明 jlabel 时的方法是 label new JLabel Hello Worl
  • java中如何围绕另一个移动对象旋转一个对象?

    我对 Java 很陌生 想要编写一个简单的太阳系统 其中月球绕地球旋转 地球绕太阳旋转 一切正常 除了月亮不想正确移动 由于地球偏离月球的初始位置 月球的自转半径会根据该距离而增大 同样 当地球接近月球惯性位置时 自转半径会减小 如果初始位
  • 仅使用 ServletContext 查找应用程序的 URL

    我正在使用 Spring MVC 编写一个 Java Web 应用程序 我有一个后台进程 它会遍历数据库并查找必须通过电子邮件发送给我的用户的通知 这些电子邮件需要包含应用程序的超链接 对于网络应用程序来说 这似乎是相当常见的模式 但我遇到
  • Java HttpURLConnection:内容长度计算

    我目前正在为 bitbucket issues RESTful API 开发一个库 我取得了很大的进步 现在我要解决这个部分更新问题 http confluence atlassian com display BBDEV Issues Is
  • 如何用java对jpg进行像素化?

    我正在尝试使用 Java 6 对 JPEG 进行像素化 但运气不佳 它需要使用 Java 而不是像 Photoshop 这样的图像处理程序 并且它需要看起来像老派 像这样 有谁能够帮助我 使用java awt image javadoc h
  • WSDL 表示中的枚举类型

    WSDL 表示如下
  • 按位非运算符

    为什么要按位运算 0 打印 1 在二进制中 不是0应该是1 为什么 你实际上很接近 在二进制中 不是0应该是1 是的 当我们谈论一位时 这是绝对正确的 然而 一个int其值为0的实际上是32位全零 将所有 32 个 0 反转为 32 个 1
  • 如何在 Eclipse 中使用 Hibernate Tools 生成 DAO?

    我在用着 Eclipse Java EE IDE Web 开发人员 版本 Indigo 发布 使用 hibernate 工具 我对 Eclipse 中的 hibernate 很陌生 所以我学习如何配置 hibernate 并使用注释生成 P
  • Java 中 LINQ 的等价物是什么? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 Java 中 LINQ 的等价物是什么 没有什么比 LINQ for Java 更好的了 Edit 现在
  • ObservableList 不更新 ArrayList

    对于学校作业 我们正在使用 JavaFX 中的 ObservableList 对象 对吗 我已经为此工作了一天多了 但无法弄清楚 老师只告诉我们 谷歌一下 所以这也没有帮助 基本上 我们正在开发一个基本的管理应用程序来跟踪人们及其家人 人们
  • java.lang.NoSuchMethodError:com.fasterxml.jackson.databind.type。使用 apache beam Spark runner 运行 go 示例时

    我想跑grades https github com apache beam tree master sdks go examples gradesapache beam go sdk 提出的示例 在一个主服务器和两个从服务器 spark2
  • 何时以及为何使用缓冲输入和输出流? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我读到这些是为了减少磁盘 网络调用开销而使用的 这在写操作的情况下似乎很好 但是进行缓冲读取有什么好处呢 如果您按字节读取文件 则每次都会进
  • 用于将字符串与通配符模式进行匹配的递归函数

    所以我一整天都在试图解决这个作业 只是无法完成 以下函数接受 2 个字符串 第二个 不是第一个 可能包含 的 星号 An 是字符串的替换 空 1个字符或更多 它可以出现 仅在s2中 一次 两次 更多或根本不出现 它不能与另一个相邻 ab c
  • Spring Boot 健康执行器 - 什么时候上线?

    我找不到任何有关 Springs Health Actuator 何时返回 UP 状态的文档 你能依靠一切吗 Components正在初始化 会不会 Controller准备好满足请求了吗 为了测试应用程序上下文是否已加载 您可以执行此自定
  • 如何使用自定义转换器访问 jOOQ 生成的例程字段作为值?

    我在访问生成例程的字段时遇到问题PL pgSQL 用户定义函数 返回JSON 数据类型结果 已经提到this https stackoverflow com q 62535195 6805866问题 这是我的结果get all orders
  • 跳过一行GridBagLayout

    我在 JFrame 上使用 GridBagLayout 我希望能够跳过一两行 但将这些行显示为空白 然后在这些行后面有一个按钮 我在文档中找不到任何方法来执行我所描述的操作 有谁知道我可以执行此操作的任何方法吗 发现它比添加空组件干净得多

随机推荐

  • 中国国家气象局天气预报信息接口

    想在自己的android应用中获得当天的天气情况 这该怎么做呢 不用担心 中国国家气象局提供了获取所在城市天气预报信息接口 通过这个接口 我们就可以获取天气信息了 中国国家气象局天气预报接口总共提供了三个 http www weather
  • 【人工智能业务概述】—人工智能的技术框架

    人工智能业务概述 人工智能的技术框架 人工智能的技术框架按照产业生态通常可以划分为基础层 技术层 应用层三大板块 其中 基础层提供了支撑人工智能应用的基础设施和技术 包括存储和处理大规模数据的能力 以及高性能的计算和通信基础设施 技术层提供
  • 怎么查看华为服务器型号,云服务器型号查看

    云服务器型号查看 内容精选 换一换 华为云帮助中心 为用户提供产品简介 价格说明 购买指南 用户指南 API参考 最佳实践 常见问题 视频帮助等技术文档 帮助您快速上手使用华为云服务 根据后端云服务器组的ID查询后端云服务器组详情 GET
  • FFmpeg编译与集成

    Java是 write once run anywhre 但 C 不一样 各平台均有差异 无法只写一次 而且各个平台的编译都不一样 比如android的ndk工具链 不同平台的库都是不一样的 本文主要讲解下 ffmpeg 在 win 平台下
  • 【Java基础篇】一文搞懂Java方法的调用与重载(超详细)

    个人主页 兜里有颗棉花糖 欢迎 点赞 收藏 留言 加关注 本文由 兜里有颗棉花糖 原创 收录于专栏 JavaSE primary 目录 一 方法的概念以及使用 1 1什么是方法 1 2方法定义 1 3方法调用的执行过程 1 4形参和实参的关
  • Python —— PyQT5 安装及配置

    PyQT5 安装及配置 下载离线安装包 测试 Pycharm配置qt designer扩展 配置 QTdesigner 配置PyUIC 配置PyRCC 测试扩展的可用性 如果报错 下载离线安装包 PyQT5 5 15 whl 文件大概60M
  • C# 9.0 新特性预览 - 类型推导的 new

    前言 随着 NET 5 发布日期的日益临近 其对应的 C 新版本已确定为 C 9 0 其中新增加的特性 或语法糖 也已基本锁定 本系列文章将向大家展示它们 目录 C 9 0 新特性预览 类型推导的 new C 9 0 新特性预览 空参数校验
  • python输出中文字符

    coding utf 8 import as import matplotlib pyplot as plt 解决中文显示问题 plt rcParams font sans serif SimHei plt rcParams axes un
  • C语言---离散数学实验--集合及二元关系的应用

    目录 集合的运算 题目要求 代码 等价关系的判定 题目要求 代码 N元关系 题目描述 代码 集合的运算 题目要求 一 集合的运算 1 用数组A B C E表示集合 输入数组A B E 全集 输入数据时要求检查数据是否重复 集合中的数据要求不
  • 网络安全和黑客技能:15本必读书籍推荐

    前言 网络安全和黑客技能紧密相连 想要有效地防范黑客攻击 了解黑客的技能和思维方式非常重要 而要想成为一名合格的白帽黑客 也需要深入理解网络安全的基本原理和最佳实践 本文将介绍15本网络安全和黑客书籍 既包括了防范黑客攻击的指南书籍 也包括
  • ubuntu配置VLAN的方法

    目录 前言 一 VLAN是什么 二 Ubuntu如何配置VLAN IP 1 依赖安装 2 创建VLAN 总结 前言 在做someip相关开发的时候需要使用到VLAN 这里介绍如何在ubuntu上创建VLAN 一 VLAN是什么 VLAN V
  • RFID技术的优势

    什么是RFID技术 RFID射频识别是一种非接触式的自动识别技术 它通过射频信号自动识别目标对象并获取相关数据 识别工作无须人工干预 可工作于各种恶劣环境 EFID技术可识别高速运动物体并可同时识别多个标签 操作快捷方便 短距离射频产品不怕
  • 性能测试总结

    性能调优是什么 我们为什么要进行性能调优 主要是由以下几个点来考虑 1 编写的新应用上线前在性能上无法满足需求 这个时候需要对系统进行性能调优 2 应用系统在线上运行后随着系统数据量的不断增长 访问量的不断上升 系统的响应速度通常越来越慢
  • object-fit和object-position实现图片原比例裁剪不拉伸适应

    img标签的图片设置width 100 height 211px 默认图片拉伸或压缩以适应此宽高 原有 但是这样太丑了 所以我们需要把图片裁剪一下 让它不拉伸以原有比例填充屏幕 首先使用到object fit这个属性 objtct fit
  • 【统计模拟及其R实现】逆变换 / 筛选法 / 合成法 上机习题答案(超详细)

    课本 统计模拟及其R实现 肖枝红 朱强 武汉大学出版社 参考课件 第三章 随机数 浙江大学数学科学学院 目录 1 逆变换法 2 筛选法 3 合成法 1 逆变换法 题目1 用逆变换方法生成如下密度函数的随机变量 要求写出R程序 Cauchy概
  • 基于python的端口扫描(升级版)

    今天给大家带来一个用python写的端口扫描小程序 需要借助一个python的库 Scapy是一个强大的Python库 用于构建和发送网络数据包 以及对网络进行各种类型的分析和操作 pip install scapy 通过Scapy 您可以
  • modbus详尽中文资料、软件、代码

    modbus详尽中文资料 软件 代码
  • linux bootarg 数组,Linux启动bootargs参数分析

    Linux启动bootargs参数分析 Written by leeming 这几天刚好在看linux c语言启动 现在就顺便把内核在启动时解析bootargs这一块单独拎出来讲解下 内核对于bootargs的解析分为几块 1 setup
  • linux下使用C语言操作MYSQL数据库(API使用libmysqlclient-dev)

    文章目录 运行环境 一 准备工作 1 在Ubuntu上准备mysql开发环境 2 创建测试数据库与表 二 建立与mysql的连接 1 在C文件中引入头文件 2 初始化mysql与数据库的通道 3 与mysql建立真实连接 三 添加操作 CR
  • java - 锁粒度

    最近工作有个需求 需要加锁保证操作的原子性 但在一定程度上我想着可以根据业务类型对锁进行细化 于是简单的写了一个demo进行验证 先来看看synchronized的demo import java util concurrent Concu