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

在分布式场景下可以使用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加锁么?

首先说结论&#xff0c;在分布式系统中&#xff0c;单纯使用 Java 中的 synchronized 关键字是无法满足需求的&#xff0c;下面从 synchronized 的作用原理、在分布式场景下的局限性以及替代方案等方面详细分析。 一、synchronized 的作用原理 在 Java 中&#xff0c;synchron…...

LeetCodehot 力扣热题100 从前序与中序遍历序列构造二叉树

初始版本 这段代码实现了根据前序遍历和中序遍历重建二叉树。下面我将详细解释每一行的作用&#xff0c;并逐步讲解算法的思路和运行步骤。 代码及注释 class Solution {public:// buildTree 函数用来根据前序遍历(pre)和中序遍历(in)重建二叉树TreeNode* buildTree(vector<…...

Day45(补)【软考】2022年下半年软考软件设计师综合知识真题-计算机软件知识1

文章目录 2022年下半年软考软件设计师综合知识真题第1章 计算机系统基础知识(12/38)计算机软件知识1-6/6哲学概念及收敛思维&#xff1a;是Python程序语言中&#xff0c;处理异常的结构集合&#xff0c;和这个集合之外的结构的区分&#xff0c;考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 图形库&#xff0c;它的作用是为开发者提供一个高层次的绘图接口&#xff0c;方便他们进行 2D 图形渲染&#xff08;比如绘制文本、形状、图像等&#xff09;。Skia 本身不直接管理 GPU 或进行底层的渲染工作&#xff0c;而是通过 底层图…...

浏览器打开Axure RP模型

1&#xff0c;直接使用chrome打开&#xff0c;提示下载插件 2&#xff0c;需要做一些操作 打开原型文件&#xff0c;找到resources\chrome\axure-chrome-extension.crx文件&#xff0c;这就是我们需要的Chrome插件。 将axure-chrome-extension.crx文件后缀名改为axure-chrome…...

【计算机网络】数据链路层数据帧(Frame)格式

在计算机网络中&#xff0c;数据帧&#xff08;Frame&#xff09; 是数据链路层的协议数据单元&#xff08;PDU&#xff09;&#xff0c;用于在物理介质上传输数据。数据帧的格式取决于具体的链路层协议&#xff08;如以太网、PPP、HDLC 等&#xff09;。以下是常见数据帧格式的…...

平面与平面相交算法杂谈

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

web集群(LVS-DR)

LVS是Linux Virtual Server的简称&#xff0c;也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项 目&#xff0c;它的官方站点是 www.linuxvirtualserver.org。现在LVS已经是 Linux标准内核的一部分&#xff0c;在 Linux2.4内核以前&#xff0c;使用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请求&#xff08;最简单的方式&#xff09;&#xff1a; //home.html // 示例&#xff1a;提交表单数据到后端 const submitForm async (formData) > {try {const response await fetch(http://your-backend-url/api/submit, {method: POST,head…...

Flutter中 List列表中移除特定元素

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

DeepSeek从入门到精通(清华大学)

​ DeepSeek是一款融合自然语言处理与深度学习技术的全能型AI助手&#xff0c;具备知识问答、数据分析、编程辅助、创意生成等多项核心能力。作为多模态智能系统&#xff0c;它不仅支持文本交互&#xff0c;还可处理文件、图像、代码等多种格式输入&#xff0c;其知识库更新至2…...

动态规划:解决复杂问题的高效策略

动态规划&#xff08;Dynamic Programming&#xff0c;简称 DP&#xff09;是一种在数学、管理科学、经济学、计算机科学等领域中广泛使用的算法设计技术。它通过将复杂问题分解为更简单的子问题&#xff0c;并通过存储子问题的解来避免重复计算&#xff0c;从而高效地解决问题…...

【kafka系列】Kafka事务的实现原理

目录 1. 事务核心组件 1.1 幂等性生产者&#xff08;Idempotent Producer&#xff09; 1.2 事务协调器&#xff08;TransactionCoordinator&#xff09; 1.3 事务日志&#xff08;Transaction Log&#xff09; 2. 事务执行流程 2.1 事务初始化 2.2 发送消息 2.3 事务提…...

网络将内网服务转换到公网上

当然&#xff0c;以下是根据您提供的描述&#xff0c;对内网端口在公网上转换过程的详细步骤&#xff0c;并附上具体例子进行说明&#xff1a; 内网端口在公网上的转换过程详细步骤 1. 内网服务配置 步骤说明&#xff1a; 在内网中的某台计算机&#xff08;我们称之为“内网…...

c#自动更新-源码

软件维护与升级 修复漏洞和缺陷&#xff1a;软件在使用过程中可能会发现各种漏洞和缺陷&#xff0c;自动更新可以及时推送修复程序&#xff0c;增强软件的稳定性和安全性&#xff0c;避免因漏洞被利用而导致数据泄露、系统崩溃等问题。提升性能&#xff1a;通过自动更新&#x…...

爬虫实战:利用代理ip爬取推特网站数据

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

git使用,注意空格

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

业务系统对接大模型的基础方案:架构设计与关键步骤

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

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 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 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; 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&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...