5

int単純な変数が複数のスレッドによって操作される可能性があるAndroidのようなマルチスレッド環境ではint、データメンバーとしてを使用することが依然として正当化される状況はありますか?

ローカル変数として、それintへの排他的アクセス権を持つメソッドのスコープに限定されます(したがって、変更の開始と終了は常に同じスレッド内にあります)、パフォーマンス的には完全に理にかなっています。

ただし、データメンバーとして、アクセサーによってラップされている場合でも、よく知られている同時インターリーブ変更の問題が発生する可能性があります。

したがって、「安全にプレイする」ことは、全面的に使用できるように見えますAtomicInteger。しかし、これはひどく非効率的なようです。

スレッドセーフなintデータメンバーの使用例を教えてください。

4

5 に答える 5

8

常にAtomicIntegerをデータメンバーとして使用しない理由はありますか?

はい、常に使用するとは限らないのには十分な理由がありますAtomicInteger。 基になる値 を設定/取得するために使用されているローカルおよび他の構成よりも構成がAtomicInteger原因で、少なくとも1桁遅くなる可能性があります(おそらくそれ以上) 。これは、アクセスするたびにメモリバリアを越えることを意味します。これにより、問題のプロセッサでキャッシュメモリがフラッシュされます。volatileintUnsafeintvolatileAtomicInteger

また、すべてのフィールドを作成したからといってAtomicInteger、複数のフィールドにアクセスしているときの競合状態から保護することはできません。volatile、、synchronizedおよびAtomic*クラスをいつ使用するかについて適切な決定を下す以外に方法はありません。

たとえば、スレッドプログラムで信頼できる方法でアクセスしたいクラスに2つのフィールドがある場合、次のようにします。

synchronized (someObject) {
   someObject.count++;
   someObject.total += someObject.count;
}

これらのメンバーの両方が2回AtomicIntegerアクセスする場合はvolatile、1つではなく2つのメモリバリアを通過します。また、割り当ては、Unsafe内の操作よりも高速ですAtomicInteger。また、(上記のブロックとは対照的に)2つの操作でのデータの競合状態のsynchronizedため、の正しい値が得られない場合がありますtotal

スレッドセーフなintデータメンバーの使用例を教えてください。

それを作成することを除いて、それをマークするか、を使用することを除いfinalて、スレッドセーフなデータメンバーのためのメカニズムはありません。すべてのフィールドでスレッドセーフをペイントする魔法の方法はありません。もしあれば、スレッドプログラミングは簡単でしょう。課題は、ブロックを配置する適切な場所を見つけることです。でマークする必要がある適切なフィールドを見つけるため。使用する適切な場所と友達を見つけるため。intvolatileAtomicIntegersynchronizedvolatileAtomicInteger

于 2012-06-20T18:02:56.983 に答える
1

効率的に不変intである場合は、計算を犠牲にして同期を保証しないことで回避できます。例はhashCode

int hash = 0;

public int hashCode(){
   if(hash == 0){
     hash = calculateHashCode(); //needs to always be the same for each Object
   }
   return hash;
}

ここでの明らかなトレードオフは、同じハッシュ値に対して複数の計算が行われる可能性ですが、代替手段がsynchronizedhashCodeの場合、はるかに悪い影響を与える可能性があります。

これは冗長ですが、技術的にはスレッドセーフです。

于 2012-06-20T18:07:07.143 に答える
0

それはそれがどのように使われるかに依存します。その他のデータ。クラスは動作をカプセル化するため、多くの場合、変数は他の変数がないとほとんど意味がありません。このような場合、1つの整数だけでなく、一緒に(またはオブジェクト全体に)属するデータメンバーを保護(*)する方がよい場合があります。これを行うAtomicIntegerと、不必要なパフォーマンスヒットになります

(*)共通のスレッドセーフメカニズムを使用する:ミューテックス、セマフォ、モニターなど。

于 2012-06-20T18:04:52.833 に答える
0

スレッドセーフは、アトミックintの割り当てだけでなく、コードの一貫性を保つためにロックパターンを注意深く設計する必要があります。

Accountパブリックデータメンバーを持つ2つのクラスがある場合はBalance、次の簡単なコードを検討してください。

Account a;
...
int withdrawal = 100;
if(a.Balance >= withdrawal)
{
    // No atomic operations in the world can save you from another thread
    // withdrawing some balance here
    a.Balance -= withdrawal
}
else
{
   // Handle error
}

率直に言って。実生活では、アトミックな割り当てを持つだけで、実生活の並行性の問題を解決できることはめったにありません。

于 2012-06-20T18:30:16.627 に答える
0

私はグーグルがOPを見て、より明確になるように主題に関する彼らの文書を更新したと思います:

「AtomicIntegerは、アトミックにインクリメントされるカウンターなどのアプリケーションで使用され、整数の代わりとして使用することはできません。」

https://developer.android.com/reference/java/util/concurrent/atomic/AtomicInteger

于 2020-11-11T01:21:02.500 に答える