Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我们可以对每个条目使用Synchronized而不是ConcurrentHashMap吗?_Java_Hashmap_Synchronized - Fatal编程技术网

Java 我们可以对每个条目使用Synchronized而不是ConcurrentHashMap吗?

Java 我们可以对每个条目使用Synchronized而不是ConcurrentHashMap吗?,java,hashmap,synchronized,Java,Hashmap,Synchronized,这就是问题所在:我们需要一个哈希表,其条目是线程安全的 假设我有一个哈希表,并且我想安全地增加其中一个条目的值:下面是确定的吗 HashMap<String , Long> hashTable = new HashMap<String, Long>(); 我认为它比ConcurrentHashMap好,因为它只锁定一个条目,不像ConcurrentHashMap使用bucket,将一组条目锁定在一起 更重要的是,我不知道如何使用COncurrenHashMap安全地增加

这就是问题所在:我们需要一个哈希表,其条目是线程安全的

假设我有一个哈希表
,并且我想安全地增加其中一个条目的值:下面是确定的吗

HashMap<String , Long> hashTable = new HashMap<String, Long>();
我认为它比ConcurrentHashMap好,因为它只锁定一个条目,不像ConcurrentHashMap使用bucket,将一组条目锁定在一起

更重要的是,我不知道如何使用COncurrenHashMap安全地增加它。例如,我认为以下代码不正确:

 ConcurrentHashMap<String , Long> hashTable = new ConcurrentHashMap<String, Long>();


 Long value = hashTable.get("key");
 value++;
 hashTable.put("key", value);
ConcurrentHashMap哈希表=新的ConcurrentHashMap();
Long value=hashTable.get(“key”);
值++;
hashTable.put(“键”,值);
我认为这是不正确的,因为两个线程可以一个接一个地读取密钥,然后一个接一个地写入,最后得到一个错误的值


伙计们,你们觉得怎么样?

你们提出的方法不是线程安全的,因为初始的
哈希表.get()
操作——通过它获取要同步的对象——相对于其他线程,它本身并没有同步,而其他线程使用的是与同一个键关联的值。此外,您的代码没有考虑将新值添加到映射或从映射中删除键的可能性(所谓的“结构修改”)。如果发生这种情况,不管键是什么,那么这些操作必须与对映射的所有其他访问同步

但是,您是对的,
ConcurrentHashMap
也不能解决这些问题。就其提供的单个操作而言,它是线程安全的,其中包括
Map
本身没有定义的一些操作,但是必须作为一个不间断单元执行的一系列操作仍然需要通过同步进行保护

我建议一种稍微不同的方法:使用
ConcurrentHashMap
AtomicLong
,它是可变的,作为您的值类型,而不是
Long

ConcurrentHashMap<String, AtomicLong> map;
putIfAbsent()
确保值对象不会被冲突的put操作阻塞。使用
AtomicLong
避免了联合同步多个操作的需要,因为只需要一个映射访问——检索到的值由访问它的所有线程共享,并且可以自动更新,而无需进一步访问映射

如果可以确定映射已经具有给定键的映射,则可以简单地执行以下操作:

AtomicLong value = map.get(key);
long updatedValue = value.incrementAndGet();
无论如何,我认为这是你所能为你描述和暗示的操作做的最好的事情

更新: 你甚至可以考虑将这两种方法结合起来:
AtomicLong value = map.get(key);

if (value == null) {
    value = map.putIfAbsent(key, new AtomicLong(0));
}

long updatedValue = value.incrementAndGet();

这就假定,对于给定的键,没有映射的情况相对较少,并且在这种情况下,它避免了创建新的
AtomicLong
。如果没有找到映射,则必须再次访问映射,以确保存在映射并获取相应的值,但如果要避免同步,这里仍然需要
putIfAbsent()
,因为两个线程可能同时尝试为同一个键添加映射。当需要添加一个新条目时,这样做的成本会更高,但它可能会比我的第一个建议平均成本更低。但是,与任何性能问题一样,测试也是必不可少的。

您有任何性能数据吗?金钱就是在这种情况下说话的,如果你真的相信你有什么有价值的东西,你应该发布一些数字,让人们有信心甚至可以看看你的算法。你建议你有一个比ConcurrentHashMap在并发环境中更正确或更有效的Map版本。除了检查,你的证据是什么?不,我在问你:这样行吗?@MohammadRoohitavaf,首先,重要的是要理解,与
long
基本值不同,
long
对象是不可变的。因此,您不能实际增加一个
Long
;如果尝试,结果将是具有所需值的不同对象。不同的对象有它自己的独立监视器(锁),因此持有一个监视器的线程不会与持有另一个监视器的线程同步。这也是为什么在您的版本中,您必须将更新后的值放入映射中,否则映射将继续保留旧值。@MohammadRoohitavaf,其次,您需要识别您的版本在由
hashTable.get()
返回的对象上进行同步,但在此之前,
hashTable.get()将
必须执行。在执行过程中,线程读取映射的内部数据结构,以查找给定键的条目并提取相关值;如果另一个线程在两个线程之间没有某种形式的同步的情况下修改这些内部数据结构中的任何一个,那么您的程序就没有正确地同步。@MohammadRoohitavaf,对映射的任何结构修改都可以修改映射的内部状态的一部分,映射上的任何其他操作都将读取这些内部状态。具有给定键的任何
put()
都将修改具有相同键的
get()
将读取的映射内部状态的一部分。因此,这些操作需要与初始的
get()
同步,但在建议的代码中,它们不是。因此,您的代码没有正确同步,也就是说,不是线程安全的。谢谢,我想我明白了。但是关于Long的不兼容性,我尝试了以下代码:longl=newlong(0);l++;系统输出打印LN(l);它很好用,可以打印1。那么,这不表明我们可以增加一个长对象吗?@MohammadRoohitavaf,不,你的代码没有表明你可以增加一个
Long
。对
l++
的求值会取消对
Long
的装箱,以获得
Long
,从而增加
AtomicLong value = map.get(key);
long updatedValue = value.incrementAndGet();
AtomicLong value = map.get(key);

if (value == null) {
    value = map.putIfAbsent(key, new AtomicLong(0));
}

long updatedValue = value.incrementAndGet();