Android runOnUiThread线程安全

时间:2013-08-05 10:47:51

标签: java android concurrency

我想知道我对特定问题的处理是否是线程安全的(可能不是,这就是我要问的原因)。假设我们有这个代码,在非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代码,那么最好的方法是什么?

由于

3 个答案:

答案 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访问它。