かかわらず、複数のスレッドがクラスにアクセスする方法の、および呼び出し元のコードに同期を必要としない、それが正しい動作を表示することができます。
スレッドセーフないくつかの方法:
1.不変
不変(不変)オブジェクトはスレッドセーフでなければならない、あなたはどのようなセキュリティ対策のスレッドを実行する必要はありません。限り不変オブジェクトが正しく出て構成された、あなたは複数のスレッド間で一貫性のない状態でそれを見ることはありません。マルチスレッド環境、満たすために不変、スレッドセーフなオブジェクトを作ってみる必要があります。
あなたはタイプを変更することはできません。
- 基本データ型のキーワード最終変更
- ストリング
- 列挙型
- 部品番号、サブクラス、ダブル値とロング、BigIntegerのBigDecimalのおよび他の大規模なデータ・タイプをパッケージの他の種類として。しかし、クラスの同一の原子とのAtomicInteger AtomicLong数は可変です。
コレクション型の場合、あなたは不変のセットを取得するためにCollections.unmodifiableXXX()メソッドを使用することができます。
2.ミューテックス同期
悲観的同時方式に属しミューテックス同期は、彼らは常に、それは確かに問題になり、右同期対策を行うにはないと思います。かどうかは、実際に競争力のあるデータの共有があるだろう、それはロックされなければならないが、ユーザーモードカーネルモードの変換、およびロックカウンタのメンテナンス(概念モデルは、ここで議論し、実際には、仮想離れて不要なロックを最適化する機会の大部分です)ブロックされたスレッドのチェックはして他の操作をウェイクアップする必要があります。
同期とReentrantLockの使用。
3.ノンブロッキング同期
共有データには、他のスレッドの競合が存在しない場合に行うことが最初の、そして操作が成功したことを、そうでない場合は代償措置(それが成功するまで再試行保つ)を取る:私たちは、衝突検出に基づく楽観的同時方式を使用することができます。多くのリアライズこの楽観的同時方式がスレッドである必要はありませんがブロックされているので、この操作は、同期非ブロック同期と呼ばれています。
- CAS
楽観的ロックと衝突検出動作は、(ハードウェアによって行われる)の原子を含む二工程が必要
アトミック操作のハードウェアサポートが最も典型的である:比較およびスワップ(コンペアアンドスワップ、CASが )。CAS命令は3つのオペランド、すなわちメモリアドレスV、古いの期待値と新しい値B. Aが必要です 動作は、Vの値がAに等しい場合にのみ実行されると、それはV Bの値を更新します - AtomicInteger
整数原子のAtomicIntegerクラスメソッド内JUCパッケージクラスCAS安全でない操作を呼び出します。//使用了 AtomicInteger 执行了自增的操作。 private AtomicInteger cnt = new AtomicInteger(); public void add() { cnt.incrementAndGet(); } // incrementAndGet() 的源码,它调用了 Unsafe 的 getAndAddInt() 。 public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } //getAndAddInt() 源码 //var1 指示对象内存地址,var2 指示该字段相对对象内存地址的偏移 //var4 指示操作需要加的数值,这里为 1 public final int getAndAddInt(Object var1, long var2, int var4) { int var5; //在一个循环中发生冲突的做法是不断的进行重试。 do { //得到旧的预期值 var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));//来进行 CAS 比较, //如果该字段内存地址中的值等于 var5,那么就更新内存地址为 var1+var2 的变量为 var5+var4。 return var5; }
- ABAの
変数は、A値の初期読み取りがある場合、時間は、その値がBに変更され、後で戻ってAに変更された、CAS操作が誤って、それが変更されたことがないと信じています
JUCパッケージAを提供します可変バージョンの値を制御することにより、CASの正確性を確保することができ、この問題を解決するための原子参照クラスAtomicStampedReference標識。、ABAの問題を解決する伝統的な相互排他の同期を使用する必要がアトミッククラスよりも効率的である可能性がある場合ABAの問題は、ほとんどの場合、プログラムの同時妥当性には影響を与えません。
4.ノー同期方式
保証スレッドセーフに、それは必ずしも同期されません。この方法は、同期の精度を確保するためにあらゆる措置なしに、それは当然、データの共有を伴わないかどうか。
1.スタッククローズ
複数のスレッドが同じメソッドのローカル変数にアクセスすると、ローカル変数をスレッドプライベートに属する、仮想マシンのスタックに格納されているので、それはスレッドの安全性の問題ではありません。
2.スレッドローカルストレージ
必要なデータでコードの一部を他のコードと共有しなければならない場合、それは同じスレッド内の共有データの実装を確保することができれば、コードを確認します。我々は、データを同期するだけでなく、問題を確実にするために必要はスレッド間の競合が発生しませんので、私たちは、同じのスレッドに制限され、可視範囲でデータを共有することができることを保証することができます。
最も重要なのは、(スレッドごとのリクエスト)アプローチ「サーバスレッドへの要求に対応し、」Webアプリケーションの相互作用モデルの古典的な例であり、広く使われている。このアプローチは、Webサーバーアプリケーションの多くはスレッドローカルを使用することができますスレッドの安全性の問題を解決するためのストレージ。
あなたは、スレッドローカルストレージを実装するためにjava.lang.ThreadLocalクラスを使用することができます。
//thread1 中设置 threadLocal 为 1,而 thread2 设置 threadLocal 为 2。
//过了一段时间之后,thread1 读取 threadLocal 依然是 1,不受 thread2 的影响。
public class ThreadLocalExample {
public static void main(String[] args) {
ThreadLocal threadLocal = new ThreadLocal();
Thread thread1 = new Thread(() -> {
threadLocal.set(1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadLocal.get());
threadLocal.remove();
});
Thread thread2 = new Thread(() -> {
threadLocal.set(2);
threadLocal.remove();
});
thread1.start();
thread2.start();
}
}
手動で、古典的なThreadLocalのメモリリークや自社のビジネスを混乱さえ危険を避けるために、()を削除し、各使用ThreadLocalの後に呼び出すことが可能であるべきです。
3.リエントラントコード(純粋なコード)
それは、(再帰呼び出し自体を含む)のコードの別の部分を実行するために有効に任意のタイムコードの実行で中断が、エラーなしで制御、元のプログラムを返却後にすることができます。
渡された状態量のパラメータで使用される一般的なヒープメモリ内のデータやシステムリソースに依存しない、非リエントラントのように、呼び出すことはありません