我对多线程有几个问题(我想安全,快速地完成我的小项目)。
我有一个图书馆。我将用户请求添加到文件中。
public static volatile HashMap<String, GooglePlayGame> games = new HashMap<>(500);
在每个应用程序启动时,我使用静态块中的文件(json + Jackson)初始化此哈希图:
static {
TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, GooglePlayGame.class);
try {
games = mapper.readValue(new File("games.json"), mapType);
} catch (IOException e) {
log.error(e.getMessage());
}
}
将处理每个用户的请求(使用特殊命令/ library),然后将新对“ key-value”添加到全局哈希图中,当然,如果key不存在(请使用containsKey进行检查)。然后使用此哈希图(而不是来自文件)。
然后我想将新的配对写入文件。为此,我想创建一个新线程,如下所示:
Thread thread = new Thread(() -> {
try {
mapper.writeValue(new File("games.json"), games);
} catch (IOException e) {
e.printStackTrace();
}
});
thread.start();
问题:
1)“易失性”有帮助吗? 是否可以保证在写入文件时始终能看到所有最后添加的对?
2)如果.. 写入文件不是每对新文件,而是每10对新文件?这该怎么做?使用CountDownLatch吗?如果是,如何正确组织呢?我不太擅长多语言阅读。 但是,如果程序崩溃并且我收到9个新请求,这些对将丢失!
3)顺便说一句,我是在这里创建一个新文件还是仅覆盖旧文件? 如果我总是创建新文件,这有点不好。杰克逊是创建新文件还是覆盖旧文件?
答案 0 :(得分:1)
1)在这种情况下,volatile
关键字无法满足您的期望。当搜索它的功能时,可能会有些误导。您会发现“ volatile
关键字保证对所有变量的所有写入均对所有线程可见”。这意味着当您将新值(新对象)分配给变量时,它将可见。但是,如果更改分配给该变量的对象,则这些更改不一定对所有线程可见。
在您的情况下,您修改Hashmap而不是变量,因此它可能不可见。您应该考虑使用一些专用的线程安全的内置集合,例如ConcurrentHashMap
2)如果发生崩溃,您不能真正确保将所有数据都写入文件。在每次输入之后写入数据总是更安全,但这取决于它发生的频率。如果是每分钟一次,最好一次写入1,如果是每秒数千次,则应考虑进行批量写入。
3)我认为自己进行测试应该很容易。另外,它与关于多线程的主要问题并没有真正的关系。
答案 1 :(得分:1)
这是您使用volatile
关键字的主要原因:
如果您有一些volatile ... x;
,则在线程B观察到分配之后,线程A在分配x = v;
之前所做的任何操作对线程B都是可见的。
final XType v = ...;
volatile XType x = ...some value other than v...;
AType a;
BType b;
CType c;
在线程A中:
a = ...;
b = ...;
x = v;
c = ...;
在线程B中:
while (x != v) {
...sleep, or spin, or maybe do some useful work...
}
...guaranteed to see the new values of a, and b here.
...No guarantee about c. Could see the old value or the new value.
但请注意!触发该行为的是分配 x = v;
您的程序初始化了volatile
变量games
,但是您的程序没有地方分配 games
。程序中的任何内容都不会触发games
的易失性。关键字在您的特定示例中无效。