您的一般结构不是线程安全的
启动整个进程的线程检查myMap并在可能的另一个线程中启动执行。
if (myMap != null) {
doSomethingInAnotherThread();
}
// something can set `myMap` to null here...
计划运行的代码将在某个时候执行
void inAnotherThread() {
myMap.access();
}
但没有更多的保证myMap与以前一样。如果有线程可以改变myMap所指的内容,那么做
void inAnotherThread() {
if (myMap != null) {
myMap.acess();
}
}
仍然不是线程安全的,因为您访问myMap了两次,并且每次都可能不同。例如,它在内部不为空,if但null一旦您访问它。一种解决方案是复制参考,这样当您使用它时,没有任何东西可以更改该参考的本地副本。
void inAnotherThread() {
Map localReference = myMap;
if (localReference != null) {
localReference.acess();
}
}
这是否是线程安全的取决于myMap. 对于一个是否是volatile(或final)。如果是:保证其他线程可以看到所指内容的最新版本myMap,如果不是:不保证。(注意:我认为runOnUiThread建立了一个happens-before关系,因为它在内部同步,因此您应该有某种保证可以看到参考的最新版本)
一旦你引用了正确的Map实例,接下来的一点就是你可以安全地使用它。一个简单HashMap的不是线程安全的使用。如果您调用.get()它,如果 - 同时 - 另一个线程调用put/ remove/.. 并因此在.get访问它时更改数据,它仍然可能会炸毁您。
您可以将它包装起来,Collections.synchronizedMap(map)这样可以使单个操作像get原子一样,这样其他线程就不会干扰。但它仍然不是所有东西的线程安全。例如,如果您不进行外部同步,则对值进行迭代仍然会失败。这个问题也可以通过使用ConcurrentHashMap支持迭代的 a 来解决。
线程安全取决于很多因素以及您对什么是线程安全的定义。如果您可以保证myMap一旦设置为永远不会更改!= null并且您知道后台线程已完成修改myMap,那么您编写的内容已经是线程安全的,因此 UiThread 可以安全地访问它。