Java 并发递增值

2023-11-29

我一直在读关于volatile and synchronized但我一直在困惑中摸不着头脑。我希望有人能帮助我解决问题

private HashMap<String,int> map = new HashMap<String,int>();

在我的线程中

if (map.get("value") == null)
{
map.put("value",0);
}
map.put("value",map.get("value")+1);

我的目标是让所有线程共享这个map。如果我添加volatile它似乎并没有解决我的问题(我输出并看到map每次都被覆盖)。然后我尝试使用ConcurrentHashMap并添加volatile在那之前……那似乎也不起作用。根据我读到的volatile我的理解是它应该“锁定”对map when map正在被写入,然后什么时候map写入完成后锁被释放。

所以...然后我尝试添加static

private static ConcurrentHashMap<String,int> map = new ConcurrentHashMap<String,int>();

这似乎工作得很好...但是...我一直在使用static由于有关“争用”的问题(我不太明白),这不是正确的方法

提前致谢


Volatile在这里没有帮助。Volatile有利于解决能见度问题,但你还面临另一个问题:原子性.

Oh, and volatile绝对没有关系locking。它在读/写时不会获取锁,也不会释放任何东西。它的作用是这样的:所有的动作发生在之前在读取相同的易失性字段后,对易失性字段的写入将对所有其他线程可见。不涉及锁定(它们的相似之处在于释放/获取锁的内存效应完全相同)。

行动get and set不是原子的,这意味着两者之间可能会发生其他事情。

例如,一个线程将get该值,然后另一个线程将get相同的值,两者都会增加该值,然后第一个会增加set新值,那么第二个将执行相同的操作。最后的结果并不是你所期望的。

这个问题最常见的解决方案是串行访问 (ie, synchronize) 到共享变量,或者使用比较并设置 (CAS)(所以你不需要进行同步)。

1. synchronized

private final Map<String, Integer> m = new ConcurrentHashMap<String, Integer>();
synchronized incrementValue(final String valueName) {
  m.put(valueName, m.get(valueName) + 1);
}

请注意,如果您使用此解决方案,则对地图的每次访问都必须同步在同一个锁上.

2. CAS

许多 CAS 算法已经以非常高性能的方式在 JVM 中实现(即,它们使用本机代码,并且 JIT 可能使用特定于处理器的指令,您无法通过其他方式访问这些指令 - 检查类Unsafe以 Sun 的 JVM 为例)。

这里可能对您有用的一类是AtomicInteger。你可以这样使用它:

private final Map<String, AtomicInteger> m = new ConcurrentHashMap<String, AtomicInteger>();
incrementValue(final String valueName) {
  m.get(valueName).incrementAndGet();
}

CAS 算法的作用如下:

for (;;) {
  state = object.getCurrentState();
  if (object.updateValueAndStateIfStateDidntChange(state)) {
    break;
  }
}

假设该方法updateValueAndStateIfStateDidntChange是原子的,并且仅当能够更新值时才会返回 true。这样,如果另一个线程在您获取状态之后和更新值之前修改了该值,该方法将返回 false 并且循环将再次尝试。

假设您可以以不使用的方式实现该方法synchronized(并且您可以通过使用 java.util.concurrent 中的类),您将避免争用(这意味着线程等待获取另一个线程持有的锁),并且您可能会看到性能的总体改进。

我在自己写的分布式任务执行系统中大量使用了这种东西。这些任务必须全部执行一次,并且我有很多机器正在执行任务。这些任务都在单个 MySQL 表中指定。怎么做?您必须有一个列,其目的是允许实施 CAS。叫它executing。在开始任务之前,您必须执行以下操作:检索下一个任务,"update tasks set executing = 1 where id = :id AND executing = 0" and 计算更新的行数。如果您更新了 0 行,那是因为另一个线程/进程/机器已经执行了该任务(并成功执行了该“更新”查询);在这种情况下,您会忘记它并尝试下一个任务,因为您知道这个任务已经在执行。如果你更新了1行,那么就可以了,你可以执行它。

我经常使用 CAS 概念的另一个地方是我编写的一个非常动态的(就其配置而言)资源池(我主要用它来管理“连接”,即套接字,但它足够通用,可以容纳任何有点儿resource)。基本上,它计算它拥有多少资源。当您尝试获取资源时,它会读取计数器,递减它,尝试更新它(如果中间没有其他任何内容修改计数器),如果成功,那么您可以简单地从池中获取资源并将其借出(一旦计数器达到 0,就不会借出资源)。如果我发布此代码,我一定会在此处添加指向它的链接。

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

Java 并发递增值 的相关文章

  • 数组查找时间复杂度和。它是如何存储的

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

    在我的项目中 我读取了具有不同查询的多个表 并将这些结果集合并到平面文件中 我该如何实现这一目标 我的意思是 JdbcReader 直接采用 1 个选择查询 我如何自定义它 如果 JdbcCursorItemReader 不能满足您的需求
  • 修复 java 内存泄漏的学习网站

    学习修复 java 内存泄漏的最佳地点是什么 我一直试图在网络上找到好的资源 但令我失望的是 我发现正在讨论玩具示例 我还能够对小型玩具转储进行故障排除 但现实世界的应用程序转储更具挑战性 并且提供的线索很少 我尝试过 Jhat JMap
  • 如何通过keytool命令删除已经导入的证书/别名?

    我正在尝试通过 keytool 命令删除已导入的证书 keytool delete noprompt alias initcert keystore keycloak jks 但低于异常 keytool 错误 java lang Excep
  • JTable AutoCreateRowSorter 将数字排序为字符串

    我有一个 JTable JTable table new JTable String colNames c1 DefaultTableModel model new DefaultTableModel Integer x new Integ
  • 简单的 C++ 线程

    我正在尝试在 C Win32 中创建一个线程来运行一个简单的方法 我是 C 线程的新手 但对 C 中的线程非常熟悉 这是我想做的一些伪代码 static void MyMethod int data RunStuff data void R
  • Spring Batch:比较数据库之间的数据

    我有两个数据库 Oracle 和 MySQL 目标是将Oracle表中的值保存到MySQL中 要求 MySQL表中不存在数据 但我在理解 Spring Batch 时遇到了困难 步骤中 它包含itemReader itemProcessor
  • 在 Java 和 PHP 之间加密/解密字符串

    我使用 AES 加密来加密和解密服务器端的 php 和 Android 应用程序 作为客户端 之间的字符串 PHP 中的加密字符串为 HaxRKnMxT24kCJWUXaVvqDHahzurJQK sYA4lIHql U 在 Java 中是
  • 从外部 clojar 导入/使用资源

    我想做的是将一个大文件 MIDI 声音字体 打包到一个独立的 Maven repo clojar 中 然后能够以编程方式将其拉下来并从单独的项目中使用它 事实证明 这个看似简单的任务比我想象的要复杂 理想的情况是 如果有一种方法可以直接访问
  • 如何对JConsole的密码文件的密码进行加密

    我正在使用 JConsole 访问我的应用程序 MBean 并使用 password properties 文件 但根据 Sun 的规范 该文件仅包含明文格式的密码 com sun management jmxremote password
  • 序言中不允许引用

    请帮我找到这个异常的原因 我使用以下罐子 core renderer jar itext paulo 155 jar 第一个文档 xhtml lt xml version 1 0 encoding UTF 8 gt lt DOCTYPE h
  • 如何在 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 现在
  • 在Java中一个接一个地播放WAV文件

    我正在尝试玩几个WAV http en wikipedia org wiki WAV文件一个接一个 我尝试了这个方法 for String file audioFiles new AePlayWave file start 但这会同时播放它
  • 如何迭代SparseArray?

    有没有办法迭代 Java SparseArray 适用于 Android 我用了sparsearray通过索引轻松获取值 我找不到 看来我找到了解决方案 我没有正确注意到keyAt index 功能 所以我会这样做 for int i 0
  • 对于每个抛出异常的语句,try/catch 是否被视为反模式?

    我目前正在审查同事的 Java 代码 我看到很多情况下 每个可能抛出异常的语句都被封装在自己的 try catch 中 其中 catch 块都执行相同的操作 哪个操作与我的问题无关 对我来说 这似乎是一种代码味道 我记得读到过它是一种常见的
  • 当相应的 JTextfield 为空时,如何填充 JTable 中的所有项目

    我正在 Java 项目中设计一个高级搜索选项sqlite在 NetBeans 中 有5种不同JTextfields和 5 列 我想填充JTable具有相应的匹配标准 如果一个JTextfield为空 那么它应该选择该列的所有项目 我使用的查
  • 仅在java中使用数组计算50的阶乘

    我是java的初学者 我有一个作业要编写一个完整的程序 使用数组计算 50 的阶乘 我无法使用像 biginteger 这样的任何方法 我只能使用数组 因为我的教授希望我们理解背后的逻辑 我猜 然而 他并没有真正教我们数组的细节 所以我在这
  • java.lang.NoClassDefFoundError:com.google.ads.AdView

    我正在尝试将 admob 广告合并到我的应用程序中 到目前为止我已经添加了以下代码 在我的应用程序主要活动的 onCreate 方法中 adView new AdView this AdSize BANNER my code number
  • 如何在 SpringDoc OpenAPI 3 中引用文件?

    我有 Spring Boot 项目 我想在其中记录我的 API 这里是正在处理的 Web 服务的示例 ApiResponses value ApiResponse responseCode 200 content Content media

随机推荐

  • 如何通过 WebRequest 调用 MVC 操作并通过 Active Directory 验证请求?

    我知道这个标题很拗口 我已经把大部分事情都准备好了 我只需要确认我是否可以做我正在尝试的事情 我正在使用 ASP NET MVC 3 我有一个应用程序 它具有我像 Web 服务一样使用的控制器 控制器上有一个方法 它返回一个字符串 即 js
  • 如果应用程序进入后台模式,则会触发 Ondisconnect

    我有以下代码 func OnlineStatus userID String handle Auth auth addStateDidChangeListener auth user in if let user user User is
  • 如何使用正则表达式删除Python中的逗号、括号?

    这些是我的文本文件的内容 例如 abc doc data name abc name xyz 在python中打开文件后 如何删除所有括号 引号和逗号 最终输出应该是 data name abc name xyz Use ast liter
  • 在 python 2.7 中导入 nltk 的语法无效

    当我在 python 2 7 CLI 中执行以下代码时 import nltk 它显示以下错误 SyntaxError Invalid Syntax Traceback most recent call last File
  • Android Studio:Drawable 文件夹:如何放置多个 dpi 的图像?

    Hi 根据android文档drawable文件夹需要有多个子目录 用于存放不同dpi的图像 然而 在 Android Studio 中 在可绘制文件夹中创建任何子目录都会导致它根本无法检测到任何图像 另一方面 如果图像直接放置在可绘制文件
  • 多个春季批量作业

    我在 Spring Boot 中使用 Scheduled 注释来触发多个作业 以下是代码片段 EnableBatchProcessing EnableScheduling public class Config extends Defaul
  • Flutter闪屏不全屏android 12

    我正在创建一个带有闪屏的颤振应用程序 我已经用过flutter native splash然而 无论我在manifest xml styles xml和launch background xml中进行什么更改 我都无法让它填满整个屏幕 它以
  • splat over JavaScript 对象(用 new )?

    如何在不使用的情况下跨越对象ECMA6 特点 Attempt function can arg0 arg1 return arg0 arg1 function foo bar haz this bar bar this haz haz my
  • Ruby 1.9.3 用 eval 定义 var

    我正在用 Ruby 编写类似 REPL 的东西 我需要在运行时定义变量 我发现我应该使用 eval 但这里是 irb 会话的摘录来测试它 在 1 9 3 中 这在 1 8 中有效 gt eval a 3 gt 3 gt a gt NameE
  • PHP 比较数组

    无论如何 有没有使用内置函数来比较 php 中的数组 而不需要执行某种循环 a1 array 1 2 3 a2 array 1 2 3 if array are same a1 a2 code here 顺便说一句 数组值并不总是按相同的顺
  • 在 UIPasteboard 中存储 NSArray

    我有几个文本文件想要在 2 个应用程序之间传输 即同一应用程序的免费和付费版本 我正在使用 UIPasteboard 来执行此操作 文件的内容作为 NSArray 保存在内存中 因此我想将这些 NSArray 复制到粘贴板 精简版 并从粘贴
  • 使用 itextsharp 删除基于文本的水印

    根据这篇文章 从 PDF iTextSharp 中删除水印 mkl 代码适用于 ExGstate 图形水印 但我已经测试了此代码以从某些 PDF 内容后面具有基于文本的水印的文件中删除水印 例如此文件 http s000 tinyuploa
  • ReactJS 修改对象数组的特定属性

    我得到了在状态中分配的对象数组 我想用输入字段修改属性 我尝试了以下一些
  • 如何使用 Javascript 获取元素的名称?

    我正在尝试获取 Javascript 中元素的名称 含义如果该元素是 div div then div 会被退回 如果它是 img src then img 会被退回 我使用 jquery 选择一堆元素 然后对所有元素调用自定义函数 在该函
  • Pandas 0.20.2 to_sql() 使用 MySQL

    我正在尝试将数据帧写入 MySQL 表 但得到了 111 Connection refused error 我在这里遵循了已接受的答案 使用 SQLAlchemy to sql 使用 pandas 写入 MySQL 数据库 答案的代码 im
  • python Spyder 不导入 numpy

    我正在使用 python Spyder 2 2 5 和 Windows 7 python 2 7 编写脚本 一开始我尝试了所有的导入方式 from numpy import or import numpy and also import n
  • 以类名作为返回类型的方法

    我是 C 或任何类型的编程语言的新手 当我看到c 中的代码时 我发现这里有很多混乱 我想从这里澄清其中之一 方法的常见结构是
  • 从 VBA 运行 python 脚本

    设想 我正在尝试从 Excel 中的 vba 代码运行 python 脚本 代码运行没有错误 但没有产生任何结果 VBA 中的代码 Private Sub CommandButton1 Click Dim Ret Val Dim args
  • 尝试将数据附加到子值时应用程序崩溃

    我正在按照 firebase 中所示的说明进行操作 但即使在确保文本条目的类型为字符串之后 我仍然遇到崩溃 这是错误 由于未捕获的异常 InvalidPathValidation 而终止应用程序 原因 child 必须是非空字符串且不包含
  • Java 并发递增值

    我一直在读关于volatile and synchronized但我一直在困惑中摸不着头脑 我希望有人能帮助我解决问题 private HashMap