import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
public class TestLock {
private static ExecutorService executor = Executors.newCachedThreadPool();
private static Map<Integer, Integer> map = new HashMap<>(1000000);
private static CountDownLatch doneSignal = new CountDownLatch(1000);
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1000; i++) {
final int j = i;
executor.execute(new Runnable() {
@Override
public void run() {
map.put(j, j);
doneSignal.countDown();
}
});
}
doneSignal.await();
System.out.println("done,size:" + map.size());
}
}
有人说并发插入哈希表并不安全。因为哈希图将执行容量扩展操作,但是我在此处将大小设置为1000000,它将仅扩展为750,000。我在这里做1000次插入,所以我不会扩展它。因此应该没有问题。但是结果总是小于1000,出了什么问题?
答案 0 :(得分:4)
为什么哈希图不是线程安全的?
因为javadocs这么说。见下文。
您说:
有人说并发插入哈希表并不安全。
不仅仅是“某些人” 1 。 javadocs明确指出:
” 请注意,此实现未同步。。如果多个线程同时访问哈希映射,并且至少一个线程在结构上修改了该映射,则必须在外部进行同步。(结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键相关联的值不是结构上的修改。“
您问:
我在这里进行1000次插入,因此不会扩展它。因此应该没有问题。但是结果总是小于1000,出了什么问题?
这不仅仅是散列数组的扩展。不只是插入。在HashMap
上执行结构修改的任何操作都需要同步...否则您可能会得到未指定的行为。
这就是你所得到的。
1-我强烈建议您不要依赖直觉或“某些人”的说法。相反,请花些时间阅读并了解相关规范。即Javadocs和Java语言规范。
答案 1 :(得分:2)
“因为哈希图将执行容量扩展操作”不仅是HashMap
线程不安全的原因。
您必须参考Java内存模型以了解其可以提供的保证。
此类保证之一是可见性。这意味着除非满足特定条件,否则一个线程中的更改可能在其他线程中不可见。
答案 2 :(得分:1)
“问题”标题并没有真正描述您的要求。反正
在这里,您已将“容量”设置为1000000。不是大小。
容量:最初在此哈希图中要包含多少个插槽。基本上 空插槽。
大小:地图中填充的元素数。
因此,即使将容量设置为1000000,结尾处的元素也不多。因此,将通过topics = list()
t = NewTopic(topic, num_partitions=3, replication_factor=1, config={'log.retention.hours': '168'})
topics.append(t)
# Call create_topics to asynchronously create topics, a dict
# of <topic,future> is returned.
fs = a.create_topics(topics)
# Wait for operation to finish.
# Timeouts are preferably controlled by passing request_timeout=15.0
# to the create_topics() call.
# All futures will finish at the same time.
for topic, f in fs.items():
try:
f.result() # The result itself is None
print("Topic {} created".format(topic))
except Exception as e:
print("Failed to create topic {}: {}".format(topic, e))
方法返回映射中填充的元素数。它与并发问题无关。是的,由于多种原因,HashMap不是线程安全的。
答案 3 :(得分:0)
如果您在HashMap类here中看到'put'的实现,则在'synchronize'处不使用,尽管它执行了许多线程不安全的操作,例如如果未找到密钥的哈希值,则创建TreeNode,请增加modCount等等
ConcurrentHashMap将适合您的用例
答案 4 :(得分:-4)
如果您需要线程安全的HashMap
,则可以改用Hashtable类。
与新的集合实现不同,Hashtable是同步的。关于
Hashtable
的javadoc说,如果不需要线程安全的实现,建议使用HashMap代替Hashtable。
同样,如果一天需要线程安全的ArrayList
,请使用Vector
。
编辑:哦,我建议使用错误的方法。我的应用程序!
评论建议比我更好的解决方案:
Collections.synchronizedXxx()
或ConcurrentHashMap,这是这个问题的开场白。