假设我有 2 个核心的 CPU。如果我将使用 Executors.newFixedThreadPool(4) 线程运行后台处理服务,我是否更正:
- 在执行程序服务的生命周期内,单线程可以在不同的内核上运行
- 即使没有同步,如果线程 A 在核心 1 上运行其代码并在 CPU 缓存中留下共享单例的某些值,那么如果线程 B 将在同一核心上运行其代码并尝试从同一内存获取单例值具有线程 A 在缓存中留下的表示的位置 - 它将从 CPU 核心 L1 或 L2 缓存中获取它。如果线程 B 将使用同步,它将从主内存(最新版本)读取新值。一般来说,如果 CPU 核心中留下的某个线程缓存共享对象私有(private)字段的某些值 - 可以在同一核心上运行的另一个线程可以从其他线程留下的缓存中看到私有(private)成员的值。
- 如果上面的两个选项都是 true - 如果 L2 缓存将用于存储线程之间共享的(这将向映射添加新值) HashMap 实例和 L2 将在所有核心缓存之间共享 - 这是否意味着跳过非原子操作(如果我们只想查看映射中的正确/最新值),我们可以跳过同步。例如,拥有 HashMap 并在从 Map 读取现有值时跳过同步是否正确:
示例
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class Launcher {
public static void main(String[] args) throws Exception {
final Stats stats = new Stats();
final Random key = new Random();
ExecutorService service = Executors.newFixedThreadPool(2);
service.submit(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
String keyValue = String.valueOf(key.nextInt(10));
int value = stats.inc(keyValue);
System.out.println("[A] Key " + keyValue + " was incremented to " + value);
try {
TimeUnit.MILLISECONDS.sleep(1500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
});
service.submit(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
int[] values = new int[10];
for (int i = 0; i< 10; i++) {
values[i] = stats.get(String.valueOf(i));
}
System.out.println("[B] " + Arrays.toString(values));
try {
TimeUnit.MILLISECONDS.sleep(1500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
});
}
static class Stats {
private final Map<String, Number> statistics = new HashMap<String, Number>();
public int inc(String key) {
if (!statistics.containsKey(key)) {
synchronized (statistics) {
statistics.put(key, new AtomicInteger(0));
}
}
return ((AtomicInteger) statistics.get(key)).getAndIncrement();
}
public int get(String key) {
if (!statistics.containsKey(key)) {
return 0;
}
return statistics.get(key).intValue();
}
}
}
您能给我指出一些关于 Java 中多线程代码的低级管理的有值(value)的文档吗?
伙计们,我真的明白我们不应该依赖特定的架构/CPU/等。我只是好奇所描述的点的概率是否大于 0:)
提前谢谢
最佳答案
您不应该对线程看到其他线程修改的值做出任何假设,除非您同步访问或使变量可变。
任何其他行为都是不可靠的并且可能会发生变化。
请记住,Java 在 JVM 上运行,而不是直接在处理器上运行,并且有权对运行的代码进行大量优化。因此,虽然很多行为会延续下去,但你不能依赖它。特别是因为一旦您在不同的架构上或在不同的条件下运行,完全相同的字节码可能会得到不同的优化。
关于Java线程与CPU核心的关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21197409/