web-dev-qa-db-ja.com

スレッドセーフと同期

Javaは初めてです。スレッドセーフと同期のどちらかと少し混乱しています。スレッドセーフとは、問題が発生することなく、メソッドまたはクラスインスタンスを複数のスレッドで同時に使用できることを意味します。同期とは、一度に1つのスレッドのみが動作できることを意味します。

では、それらはどのように相互に関連していますか?

20
Nayak

Java Concurrency in Practice で定義されているスレッドセーフの定義は次のとおりです。

ランタイム環境によるこれらのスレッドの実行のスケジューリングやインターリーブに関係なく、複数のスレッドからアクセスされたときにクラスが正しく動作する場合、クラスはスレッドセーフであり、呼び出しコードの追加の同期やその他の調整は必要ありません。

たとえば、Java.text.SimpleDateFormatオブジェクトには、解析またはフォーマットするメソッドが呼び出されると変更される内部の可変状態があります。複数のスレッドが同じdateformatオブジェクトのメソッドを呼び出す場合、スレッドが他のスレッドが必要とする状態を変更する可能性があり、その結果、一部のスレッドによって取得された結果がエラーになる可能性があります。内部状態が破損して出力が不良になる可能性があるため、このクラスはスレッドセーフではありません。

この問題を処理する方法はいくつかあります。 SimpleDateFormatオブジェクトを必要とするアプリケーション内のすべての場所で、必要なたびに新しいインスタンスをインスタンス化できます。プログラムの各スレッドが独自のコピーにアクセスできるように、SimpleDateFormatオブジェクトを保持するThreadLocalを作成できます(各スレッドは、 1つを作成するには)、状態を保持しないSimpleDateFormatの代替を使用するか、synchronizedを使用してロックを行い、一度に1つのスレッドのみがdateFormatオブジェクトにアクセスできるようにします。ロックは必ずしも最善の方法ではありません。可能な限り共有された可変状態を回避することが最善です。

synchronizedキーワードは、メソッドまたはコードのブロックへのアクセスを制限する1つの方法です。そうしないと、スレッドセーフでないデータが破損しないようになります。このキーワードは、スレッドが特定のロック(同期がインスタンスメソッドの場合はオブジェクトインスタンス、同期が静的メソッドの場合はクラスインスタンス)、または指定された同期されたブロックを使用する場合はロックします)、それがメソッドまたはブロックに入る前に、スレッドが古いデータを表示しないようにメモリの可視性を提供します。

14
Nathan Hughes

スレッドセーフはプログラムの望ましい動作であり、synchronizedブロックはその動作を実現するのに役立ちます。スレッドの安全性を取得する方法は他にもあります(例:不変のクラス/オブジェクト)。お役に立てれば。

10
fastcodejava

スレッドセーフティ:スレッドセーフプログラムは、データをメモリの一貫性エラーから保護します。高度にマルチスレッド化されたプログラムでは、スレッドセーフプログラムは、共有データ(オブジェクト)の複数のスレッドからの複数の読み取り/書き込み操作による副作用を引き起こしません。異なるスレッドが一貫性​​エラーなしでオブジェクトデータを共有および変更できます。

synchronizedは、ThreadSafeコードを実現する基本的な方法の1つです。

詳細については、以下のSEの質問を参照してください。

「同期」とはどういう意味ですか?

高度な同時実行APIを使用してスレッドセーフを実現できます。このドキュメント page は、スレッドセーフを実現するための優れたプログラミング構造を提供します。

Lock Objects 多くの同時アプリケーションを簡略化するロックイディオムをサポートします。

Concurrent Collections は、データの大規模なコレクションの管理を容易にし、同期の必要性を大幅に減らすことができます。

Atomic Variables には、同期を最小限に抑え、メモリの一貫性エラーを回避する機能があります。

ThreadLocalRandom(JDK 7では)から擬似乱数を効率的に生成します複数のスレッド。

他のプログラミング構成については、 Java.util.concurrent および Java.util.concurrent.atomic パッケージも参照してください。

関連するSEの質問:

同期vsロック

5
Ravindra babu

多くの答えを辛抱強く読み、同時にあまり技術的ではなかった後、私は何か明確なことを言えるかもしれませんが、 Nayak はすでに上記の fastcodejava に返信していました。後で私の答えに来るが、見て

同期は、総当たりのスレッドセーフにさえ近づいていません。コード(またはメソッド)を他のスレッドが使用できないようにすることで、単一の承認済みスレッドに対して安全で破損しないようにします。

スレッドセーフとは、特定の要素にアクセスするすべてのスレッドがどのように振る舞い、どのような形式もなしにシーケンシャル(またはそうでなくても)である場合に同じように望ましい結果を得る方法です理想的な世界と同様に、望ましくない破損( pleonasm の場合は申し訳ありません)。

スレッドセーフに近づける方法の1つは、Java.util.concurrent.atomicでクラスを使用することです。

悲しいことに、finalメソッドがありません!

2
Aakash Verma

同期:1つのスレッドのみが同時に動作できます。スレッドセーフ:メソッドまたはクラスのインスタンスは、問題を発生させることなく、複数のスレッドで同時に使用できます。あなたがこの質問に関連しているなら、なぜ同期されたメソッドはスレッドセーフなのですか?あなたがより良いアイデアを得ることができるよりも。

定義によれば、これは紛らわしいようです。しかし、それを分析的に理解すれば違います。

同期とは、順番に1つずつ順番に、同時ではない[同時にではない]を意味します。同期されたメソッドでは、別のスレッドを処理することはできませんが、スレッドはすでに処理中です。同期の例:映画のチケットを購入してキューに立つ場合。あなたの前の人がチケットを受け取った後にのみ、チケットを受け取ります。

スレッドセーフな方法:複数のスレッドが同時に問題なくアクセスできるようにメソッドが安全になります。同期キーワードは、「スレッドセーフ」を実現する方法の1つです。ただし、実際には、複数のスレッドが同期されたメソッドにアクセスしようとする間、それらは順序に従って、安全にアクセスできます。実際には、それらは同時に動作しますが、リソースの同期された動作のため、同じリソース(メソッド/ブロック)に同時にアクセスできません。

メソッドが同期されると、複数のスレッドが問題なく動作できるようになるため、これは安全になります。覚えておいてください:複数のスレッド "同時に動作しない"したがって、同期されたメソッドをスレッドセーフで呼び出します。

これが理解に役立つことを願っています。

0
mbagat

Nayak、メソッドを同期として宣言すると、他のスレッドからのそのメソッドへの他のすべての呼び出しはロックされ、無期限に待機できます。 Javaは現在、Lockオブジェクトを使用してロックする他の手段も提供しています。

オブジェクトをfinalまたはvolatileとして宣言して、他の並行スレッドでのオブジェクトの可用性を保証することもできます。

ref: http://www.javamex.com/tutorials/threads/thread_safety.shtml

0
killjoy

実際には、パフォーマンスの観点から、スレッドセーフ、同期、非スレッドセーフ、非同期のクラスは次のように並べられます。

Hashtable(slower)  <  Collections.SynchronizedMap  <  HashMap(fastest)
0
Joel Mata