0

特定の問題に対する私のアプローチがスレッドセーフであるかどうか疑問に思っていました(おそらくそうではないので、私は尋ねています)。非 UI スレッドで実行される次のコードがあるとします。

if (myMap != null)
{
    runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
           Something something = myMap.get(someKey);
           // update some views and stuff                                       
        }
    });
}

ランナブルが実際に実行されるまでに myMap が有効であるという保証はないと思いますよね?その場合、 myMap != null を run() メソッド内に移動するか、そこに複製する必要がありますか? マップが null でない場合にのみ runOnUiThread コードが実行されるようにするには、どのような方法が最適でしょうか?

ありがとう

4

3 に答える 3

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
}
于 2013-08-05T10:50:59.820 に答える
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();
    }
}

myMap2回アクセスし、毎回異なる可能性があるため、それでもスレッドセーフではありません。たとえば、内部では null ではありませんifが、null一度アクセスすると。解決策の 1 つは、参照をコピーして、作業中にその参照のローカル コピーを変更できないようにすることです。

void inAnotherThread() {
    Map localReference = myMap;
    if (localReference != null) {
        localReference.acess();
    }
}

それがスレッドセーフかどうかは、に依存しmyMapます。それがvolatile(またはfinal)であるかどうかにかかわらず。そうである場合: 他のスレッドは、参照されているものの最新バージョンを参照することが保証されmyMapます。そうでない場合: 何も保証されません。(注:内部で同期するため、事前発生runOnUiThread関係が確立されていると思います。したがって、参照の最新バージョンを表示するための何らかの保証が必要です)

正しいインスタンスへの参照を取得したら、次のポイントMapは、それを安全に使用できることです。simpleHashMapはスレッドセーフではありません。呼び出し.get()ても、別のスレッドがput/ remove/.. を呼び出し、.getアクセス中にデータを変更すると、まだ爆発する可能性があります。

他のスレッドが干渉できないように、アトミックのようCollections.synchronizedMap(map)な単一の操作を行うラップすることができます。getしかし、それでもすべてに対してスレッドセーフではありません。たとえば、外部で同期しないと、値の繰り返しは失敗します。ConcurrentHashMapこの問題は、反復もサポートする を使用することで解決できます。

スレッドセーフは、多くの要因と、スレッドセーフとは何かの定義に依存します。myMap一度設定すると決して変更されないことを保証でき!= null、バックグラウンド スレッドの変更が完了myMapしているため、UiThread が安全にアクセスできることがわかっている場合、記述した内容はすでにスレッドセーフです。

于 2013-08-05T11:38:41.813 に答える