我想知道我对特定问题的处理是否是线程安全的(可能不是,这就是我要问的原因)。假设我们有这个代码,在非UI线程上运行:
if (myMap != null)
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
Something something = myMap.get(someKey);
// update some views and stuff
}
});
}
我猜我无法保证mynable在实际执行时有效,对吧?如果是这种情况,我应该在run()方法中移动myMap!= null还是只在那里复制它?如果我想确保只有在映射不为null时才执行runOnUiThread代码,那么最好的方法是什么?
由于
答案 0 :(得分:2)
这就像在执行你给出的代码之前定义myMap一样简单:
Map<String, String> myMap = new Hashmap<String, String>();
//if (myMap != null)
// {
runOnUiThread(new Runnable()
{
@Override
public void run()
{
Something something = myMap.get(someKey); //myMap won't be null
// update some views and stuff
}
});
// }
如果您要检查内部是否有任何数据,那么您可以使用 size()方法
if(myMap.size() != 0) {
//do your stuffs
}
答案 1 :(得分:1)
当您创建Runnable并将其传递给函数“runOnUiThread()”时,如果当前线程是主线程,它将立即执行或将被放入队列中并将在稍后执行,并且该对象可以是无效。如果在工作线程中检查其有效性(在Runnable的run()方法中)会更好。
答案 2 :(得分:1)
您的一般结构不是线程安全的
启动整个进程的线程检查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
建立了一个发生之前的关系,因为它在内部同步,因此您应该有某种保证来查看最新版本的引用)
下一点,一旦您引用了正确的Map
实例,您就可以安全地使用它。一个简单的HashMap
不是线程安全的。如果你打电话给.get()
,如果 - 同时 - 另一个线程调用put
/ remove
/ ..并因此更改数据.get
访问它。
你可以将它包装在Collections.synchronizedMap(map)
中,这将使单个操作像get
原子,所以其他线程不能干涉。但对于一切而言,它仍然不是线程安全的。例如。如果不进行外部同步,迭代值仍将失败。这个问题可以通过使用支持迭代的ConcurrentHashMap
来解决。
线程安全取决于很多因素以及您对线程安全的定义。你写的内容已经是线程安全的,如果你可以保证myMap
一旦被设置为!= null
就永远不会改变,并且你知道后台线程已经完成修改myMap
所以它是安全的UiThread访问它。