Java 中的 ConcurrentHashMap 和 AtomicInteger 示例
ConcurrentHashMap and AtomicInteger example in Java
我正在尝试实现以下功能:
str 数组中的每个键都应与一个从 0 开始的 Integer 相关联,并将存储在 map 中。执行后映射应该包含 str 中的所有键并且计数应该与最终值 9 一致。但是结果从 8 到 12 不等。我做错了什么?
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
public static final AtomicInteger count = new AtomicInteger(0);
public static final String[] str = {
"a", "b", "c", "d", "e", "f", "g", "h"
};
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
ExecutorService exe = Executors.newFixedThreadPool(4);
for (int j = 0; j < 100; j++) {
exe.execute(() -> {
for (int k = 0; k < 1000; k++) {
int index = k % 8;
String key = str[index];
Integer value = map.get(key);
if (value == null) {
Integer next = count.incrementAndGet();
map.putIfAbsent(key, next);
}
}
});
}
exe.shutdown();
exe.awaitTermination(5, TimeUnit.SECONDS);
System.out.println("count = " + count.get());
}
}
}
你这里有一个竞争条件:
Integer value = map.get(key); // read
if (value == null) {
Integer next = count.incrementAndGet();
map.putIfAbsent(key, next); // write
}
如果键在读取之后和写入之前由另一个线程设置,incrementAndGet()
将被执行,尽管它实际上不会被插入,因为 putIfAbsent()
是原子的。您可以使用 computeIfAbsent()
:
相对于地图自动执行条件增量
map.computeIfAbsent(key, k -> count.incrementAndGet());
我正在尝试实现以下功能: str 数组中的每个键都应与一个从 0 开始的 Integer 相关联,并将存储在 map 中。执行后映射应该包含 str 中的所有键并且计数应该与最终值 9 一致。但是结果从 8 到 12 不等。我做错了什么?
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
public static final AtomicInteger count = new AtomicInteger(0);
public static final String[] str = {
"a", "b", "c", "d", "e", "f", "g", "h"
};
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
ExecutorService exe = Executors.newFixedThreadPool(4);
for (int j = 0; j < 100; j++) {
exe.execute(() -> {
for (int k = 0; k < 1000; k++) {
int index = k % 8;
String key = str[index];
Integer value = map.get(key);
if (value == null) {
Integer next = count.incrementAndGet();
map.putIfAbsent(key, next);
}
}
});
}
exe.shutdown();
exe.awaitTermination(5, TimeUnit.SECONDS);
System.out.println("count = " + count.get());
}
}
}
你这里有一个竞争条件:
Integer value = map.get(key); // read
if (value == null) {
Integer next = count.incrementAndGet();
map.putIfAbsent(key, next); // write
}
如果键在读取之后和写入之前由另一个线程设置,incrementAndGet()
将被执行,尽管它实际上不会被插入,因为 putIfAbsent()
是原子的。您可以使用 computeIfAbsent()
:
map.computeIfAbsent(key, k -> count.incrementAndGet());