在分布式场景下可以使用synchronized加锁么?
首先说结论,在分布式系统中,单纯使用 Java 中的 synchronized
关键字是无法满足需求的,下面从 synchronized
的作用原理、在分布式场景下的局限性以及替代方案等方面详细分析。
一、synchronized
的作用原理
在 Java 中,synchronized
关键字用于实现线程同步,它可以保证在同一时刻,只有一个线程能够访问被 synchronized
修饰的代码块或方法。其本质是通过获取对象的监视器(monitor)来实现互斥访问,这是基于 JVM 层面的同步机制,作用范围仅限于单个 JVM 进程内。
以下是一个简单的 synchronized
使用示例:
public class SynchronizedExample {private int count = 0;public synchronized void increment() {count++;}public static void main(String[] args) throws InterruptedException {SynchronizedExample example = new SynchronizedExample();Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});t1.start();t2.start();t1.join();t2.join();System.out.println("Count: " + example.count);}
}
在这个示例中,increment
方法被 synchronized
修饰,确保了在同一时刻只有一个线程能够执行该方法,从而避免了多线程环境下的竞态条件。
二、在分布式场景下的局限性
分布式系统由多个独立的 JVM 进程组成,不同进程之间无法直接共享对象的监视器。synchronized
只能保证单个 JVM 内的线程同步,无法实现跨 JVM 进程的同步。因此,在分布式系统中,如果多个进程同时访问共享资源,使用 synchronized
无法保证资源的互斥访问,可能会导致数据不一致等问题。
三、分布式系统中的替代方案
为了实现分布式环境下的同步,可以使用以下几种常见的方案:
1.数据库锁
可以利用数据库的行级锁或表级锁来实现分布式锁。例如,在 MySQL 中,可以使用 SELECT ... FOR UPDATE
语句来获取行级锁。
-- 获取行级锁
SELECT * FROM distributed_lock_table WHERE lock_name = 'resource_lock' FOR UPDATE;
这种方式的优点是实现简单,不需要额外的组件;缺点是性能较差,对数据库的依赖较大。
2.Redis 分布式锁——SETNX
Redis 是一个高性能的键值存储系统,可以利用 Redis 的原子操作来实现分布式锁。常见的实现方式是使用 SETNX
(SET if Not eXists)命令。
import redis.clients.jedis.Jedis;public class RedisDistributedLock {private static final String LOCK_KEY = "distributed_lock";private static final String LOCK_VALUE = "lock_value";private static final int EXPIRE_TIME = 1000; // 锁的过期时间,单位:毫秒public static boolean acquireLock(Jedis jedis) {String result = jedis.set(LOCK_KEY, LOCK_VALUE, "NX", "PX", EXPIRE_TIME);return "OK".equals(result);}public static void releaseLock(Jedis jedis) {jedis.del(LOCK_KEY);}public static void main(String[] args) {Jedis jedis = new Jedis("localhost", 6379);if (acquireLock(jedis)) {try {// 执行临界区代码System.out.println("获取到锁,执行临界区代码");} finally {releaseLock(jedis);}} else {System.out.println("未获取到锁");}jedis.close();}
}
这种方式的优点是性能高,实现相对简单;缺点是需要额外的 Redis 服务,并且需要处理锁的过期时间和异常情况。
3.Redis 分布式锁——TryLock
事实上,Redis 实现 TryLock
也要依靠 SET
命令的原子性,通过设置特定的键值对以及过期时间来模拟锁的获取和释放。当执行 SET
命令时,如果键不存在则设置成功,相当于获取到锁;若键已存在则设置失败,代表锁已被其他客户端持有。
以下是使用 Jedis实现 tryLock
功能的示例代码:
import redis.clients.jedis.Jedis;public class RedisTryLockExample {private static final String LOCK_KEY = "distributed_lock";private static final String LOCK_VALUE = "lock_value";private static final int EXPIRE_TIME = 10000; // 锁的过期时间,单位:毫秒private Jedis jedis;public RedisTryLockExample() {this.jedis = new Jedis("localhost", 6379);}/*** 尝试获取锁* @return 如果获取到锁返回 true,否则返回 false*/public boolean tryLock() {// 使用 SET 命令的 NX(Not eXists)和 PX(过期时间)选项String result = jedis.set(LOCK_KEY, LOCK_VALUE, "NX", "PX", EXPIRE_TIME);return "OK".equals(result);}/*** 释放锁*/public void unlock() {jedis.del(LOCK_KEY);}public static void main(String[] args) {RedisTryLockExample lockExample = new RedisTryLockExample();if (lockExample.tryLock()) {try {// 模拟执行临界区代码System.out.println("获取到锁,执行临界区代码");Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();} finally {lockExample.unlock();System.out.println("释放锁");}} else {System.out.println("未获取到锁");}lockExample.jedis.close();}
}
比较SETNX和TryLock:
SETNX
的问题:使用 SETNX
命令设置锁时,无法原子性地设置锁的过期时间。若在设置完锁之后,在设置过期时间之前,客户端发生异常崩溃,就会导致锁无法释放,造成死锁。SETNX
只是单纯地判断键是否存在并进行设置,对于锁的过期时间等额外属性需要额外的命令来处理,在实现分布式锁时需要编写更多的代码来保证正确性,代码的可读性和可维护性较差。功能相对单一,仅能实现键的存在性判断和设置操作。
TryLock
实现的优势:使用 SET
命令并结合 NX
和 PX
/EX
选项可以原子性地完成锁的设置和过期时间的设置,避免了上述死锁问题。从功能语义上来说,TryLock
更符合锁的使用习惯,调用者可以直观地理解其作用是尝试获取锁,并且能够方便地结合过期时间等参数进行使用,代码逻辑更加清晰。TryLock基于 SET
命令可以利用 Redis 提供的更多特性,例如可以设置不同的过期时间单位(PX
表示毫秒,EX
表示秒),还可以结合其他命令实现更复杂的分布式锁逻辑,如可重入锁等。
四、总结
综上所述,在分布式系统中不能直接使用 synchronized
来实现同步,需要根据具体的业务场景选择合适的分布式锁方案。
相关文章:
在分布式场景下可以使用synchronized加锁么?
首先说结论,在分布式系统中,单纯使用 Java 中的 synchronized 关键字是无法满足需求的,下面从 synchronized 的作用原理、在分布式场景下的局限性以及替代方案等方面详细分析。 一、synchronized 的作用原理 在 Java 中,synchron…...
LeetCodehot 力扣热题100 从前序与中序遍历序列构造二叉树
初始版本 这段代码实现了根据前序遍历和中序遍历重建二叉树。下面我将详细解释每一行的作用,并逐步讲解算法的思路和运行步骤。 代码及注释 class Solution {public:// buildTree 函数用来根据前序遍历(pre)和中序遍历(in)重建二叉树TreeNode* buildTree(vector<…...

Day45(补)【软考】2022年下半年软考软件设计师综合知识真题-计算机软件知识1
文章目录 2022年下半年软考软件设计师综合知识真题第1章 计算机系统基础知识(12/38)计算机软件知识1-6/6哲学概念及收敛思维:是Python程序语言中,处理异常的结构集合,和这个集合之外的结构的区分,考Python集合之外的结构 哲学概念…...
luoguP8764 [蓝桥杯 2021 国 BC] 二进制问题
luogu题目传送门 题目描述 小蓝最近在学习二进制。他想知道 1 到 N 中有多少个数满足其二进制表示中恰好有 K 个 1。你能帮助他吗? 输入格式 输入一行包含两个整数 N 和 K。 输出格式 输出一个整数表示答案。 输入输出样例 输入 #1 7 2 输出 #1 3 说明/提示 对于…...
图形渲染(一)——Skia、OpenGL、Mesa 和 Vulkan简介
1.Skia —— 2D 图形库 Skia 是一个 2D 图形库,它的作用是为开发者提供一个高层次的绘图接口,方便他们进行 2D 图形渲染(比如绘制文本、形状、图像等)。Skia 本身不直接管理 GPU 或进行底层的渲染工作,而是通过 底层图…...

浏览器打开Axure RP模型
1,直接使用chrome打开,提示下载插件 2,需要做一些操作 打开原型文件,找到resources\chrome\axure-chrome-extension.crx文件,这就是我们需要的Chrome插件。 将axure-chrome-extension.crx文件后缀名改为axure-chrome…...
【计算机网络】数据链路层数据帧(Frame)格式
在计算机网络中,数据帧(Frame) 是数据链路层的协议数据单元(PDU),用于在物理介质上传输数据。数据帧的格式取决于具体的链路层协议(如以太网、PPP、HDLC 等)。以下是常见数据帧格式的…...

平面与平面相交算法杂谈
1.前言 空间平面方程: 空间两平面如果不平行,那么一定相交于一条空间直线, 空间平面求交有多种方法,本文进行相关讨论。 2.讨论 可以联立方程组求解,共有3个变量,2个方程,而所求直线有1个变量…...

web集群(LVS-DR)
LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项 目,它的官方站点是 www.linuxvirtualserver.org。现在LVS已经是 Linux标准内核的一部分,在 Linux2.4内核以前,使用LVS时必须要重新编…...

更高效实用 vscode 的常用设置
VSCode 可以说是文本编辑神器, 不止程序员使用, 普通人用其作为文本编辑工具, 更是效率翻倍. 这里分享博主对于 VSCode 的好用设置, 让 VSCode 如虎添翼 进入设置 首先进入设置界面, 后续都在这里进行配置修改 具体设置 每项配置通过搜索关键字, 来快速定位配置项 自动保存…...

win11 终端乱码导致IDE 各种输出也乱码
因为 win11 终端乱码导致IDE 各种输出也乱码导致作者对此十分头大。所以研究了各种方法。 单独设置终端编码对 HKEY_CURRENT_USER\Console 注册表进行修改对 HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processo 注册表进行修改使用命令[Console]::OutputEncoding [Syst…...
对于简单的HTML、CSS、JavaScript前端,我们可以通过几种方式连接后端
1. 使用Fetch API发送HTTP请求(最简单的方式): //home.html // 示例:提交表单数据到后端 const submitForm async (formData) > {try {const response await fetch(http://your-backend-url/api/submit, {method: POST,head…...

Flutter中 List列表中移除特定元素
在 Dart 语言里,若要从子列表中移除特定元素,可以使用以下几种方法,下面为你详细介绍: 方法一:使用 where 方法创建新列表 where 方法会根据指定的条件筛选元素,然后通过 toList 方法将筛选结果转换为新列…...

DeepSeek从入门到精通(清华大学)
DeepSeek是一款融合自然语言处理与深度学习技术的全能型AI助手,具备知识问答、数据分析、编程辅助、创意生成等多项核心能力。作为多模态智能系统,它不仅支持文本交互,还可处理文件、图像、代码等多种格式输入,其知识库更新至2…...
动态规划:解决复杂问题的高效策略
动态规划(Dynamic Programming,简称 DP)是一种在数学、管理科学、经济学、计算机科学等领域中广泛使用的算法设计技术。它通过将复杂问题分解为更简单的子问题,并通过存储子问题的解来避免重复计算,从而高效地解决问题…...
【kafka系列】Kafka事务的实现原理
目录 1. 事务核心组件 1.1 幂等性生产者(Idempotent Producer) 1.2 事务协调器(TransactionCoordinator) 1.3 事务日志(Transaction Log) 2. 事务执行流程 2.1 事务初始化 2.2 发送消息 2.3 事务提…...
网络将内网服务转换到公网上
当然,以下是根据您提供的描述,对内网端口在公网上转换过程的详细步骤,并附上具体例子进行说明: 内网端口在公网上的转换过程详细步骤 1. 内网服务配置 步骤说明: 在内网中的某台计算机(我们称之为“内网…...
c#自动更新-源码
软件维护与升级 修复漏洞和缺陷:软件在使用过程中可能会发现各种漏洞和缺陷,自动更新可以及时推送修复程序,增强软件的稳定性和安全性,避免因漏洞被利用而导致数据泄露、系统崩溃等问题。提升性能:通过自动更新&#x…...

爬虫实战:利用代理ip爬取推特网站数据
引言 亮数据-网络IP代理及全网数据一站式服务商屡获殊荣的代理网络、强大的数据挖掘工具和现成可用的数据集。亮数据:网络数据平台领航者https://www.bright.cn/?promoRESIYEAR50/?utm_sourcebrand&utm_campaignbrnd-mkt_cn_csdn_yingjie202502 在跨境电商、社…...

git使用,注意空格
第一节 安装完成后,找个目录用于存储,打开目录右击选择git bash here 命令1 姓名 回车 git config --global user.name "li" 命令2 邮箱 回车 git config --global user.email "888163.com" 命令3 初始化新仓库,下载克隆 回…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...