【发布时间】:2013-10-23 03:32:36
【问题描述】:
您好 Stackoverflow 社区,
我有一个关于线程安全的问题。如果我有一个静态地图并用不同的对象填充它,这些对象线程安全吗?如果我只有他们不写的方法?
我创建一个小例子:这种情况下getCommand线程的返回值是否安全?
如何使用 JUnit 测试线程安全性?
控制器
public class CommandController {
private static Map<String, Command> commandMap = initMap();
public static Map<String, Command> initMap() {
return new HashMap<String, Command>() {{
put("A", new CommandA());
put("B", new CommandB());
}};
}
public Command getCommand(String key) {
if(commandMap.containsKey(key)) {
return commandMap.get(key);
}
return null;
}
}
抽象类
public abstract class Command {
public abstract int calc(int value);
}
命令 A
public class CommandB extends Command {
@Override
public int calc(int value) {
value = value * 4;
return value;
}
}
命令 B
public class CommandA extends Command {
private int ab = 5;
@Override
public int calc(int value) {
return value * ab;
}
}
【问题讨论】:
-
HashMap不是线程安全的。不可变对象是,但你应该使用final。 -
为什么不
public Command getCommand(String key) { return commandMap.get(key); }? (如果键不在地图中,则返回 null) -
@assylias 这种方法会更简单,性能更高,但我认为它不会对线程安全产生任何影响(尤其是在使用 HashMap 时)。
-
这里真正的问题是类加载/初始化是否会创建同步点、内存屏障或内存刷新点。如果线程 A 导致 CommandController.class 被加载并初始化其静态字段,线程 B 会看到 CommandController 的静态字段的最新值吗?特别是如果没有明确的同步点,例如“volatile”、“final”或“synchronized”。我不知道。
-
@MikeClark 确实如此。在类完全初始化之前发生的写入在类完全初始化后可见。
标签: java multithreading design-patterns