同時プログラミング|スレッドセキュリティ


同時プログラミングはずっと企業の応用あるいは面接の中で人々の関心の重点で、この時間もJavaマルチスレッドの関連する知識を深く理解することを望んで、最終的に《Java同時プログラミング実戦》という本を選んで、何人かの大牛力作、豆弁は9.0点を採点して、このシリーズの文章はこの本のまとめと理解で、みんなに分かち合って、あなたと一緒に勉強します.
本では,正しい同時プログラムを記述するには,共有の可変状態にアクセスする際に正確な管理が必要であることが鍵であると指摘している.この記事では、同期によって複数のスレッドが同じ時刻に同じデータにアクセスすることを回避する方法についてまとめ、次の記事ではオブジェクトを共有してパブリッシュする方法について説明します.

概要
1つのオブジェクトがスレッドで安全である必要があるかどうかは、複数のスレッドにアクセスされているかどうか(オブジェクトへのアクセス方法)によって異なります.
Javaの同期メカニズムは4つあります.
  • キーワードsynchronized
  • volatileタイプ変数
  • 明示的ロック
  • 原子変数
  • 3つのスレッドが同じ可変状態変数にアクセスしているときに適切な同期がない場合、プログラムにエラーが発生し、3つの方法で修正できます.
  • は、スレッド間でこの状態変数
  • を共有しない.
  • 状態変数を不変の変数
  • に変更する.
  • アクセス状態変数は、同期
  • を用いる.

    スレッドセキュリティとは
    定義:複数のスレッドがクラスにアクセスする場合、実行環境がどのようなスケジューリング方式を採用しているか、またはこれらのスレッドがどのように交互に実行されるかにかかわらず、プライマリ・コール・コードに追加の同期や協同は必要ありません.このクラスは正しい動作を示します.
    スレッドがステータスのないオブジェクトにアクセスする動作は、他のスレッドでの動作の正確性に影響しないため、ステータス変数がないのはスレッドが安全であるに違いない.

    げんしせい
    定義:1つのスレッドが操作を実行すると、すべて実行するか、完全に実行しないか、この操作は原子です.
    競合条件
    定義:不適切な実行タイミングによる不正な結果
    一般的な競合条件のタイプは
  • 「先検査後実行」:失効する可能性のある観察結果に基づいて、ある計算
  • を判断または実行する.
  • 「読み取り-修正-書き込み」:オブジェクトの前の状態に基づいてオブジェクトの状態を定義する変換
  • .
    複合アクション
    複合オペレーションには、スレッドのセキュリティを確保するために原子的に実行しなければならない(または分割できない)オペレーションのセットが含まれています.たとえば、「チェックしてから実行」や「読み取り-修正-書き込み」などの操作は複合操作です.
    実際の状況では、クラスのステータスを管理するために既存のスレッドセキュリティオブジェクトをできるだけ使用する必要があります.

    ロック機構
    マルチスレッドでは、ステータスの一貫性を維持するには、単一の原子操作で関連するすべてのステータス変数を更新します.
    内蔵ロック
    Javaは、原子性をサポートする内蔵ロックを提供します.同期コードブロック(synchronized block)は、2つの部分を含みます.
  • ロックされたオブジェクト参照
  • もう1つはロック保護コードブロック
  • である.
    キーワードsynchronizedで修飾する方法も同期コードブロックであり,ロックはメソッド呼び出しが存在するオブジェクトである.例:
    public class SynchronizedExample{
        public sychronized void doSomething(){
            //    
        }
    }

    静的synchronizedメソッドはClassオブジェクトをロックします.
    Javaの内蔵ロックは反発ロックに相当し、このロックを持つスレッドが1つしかないことを意味します.スレッドAがスレッドBによって保持されるロックを取得しようとすると、スレッドAは、スレッドBがロックを解放するまで待機またはブロックしなければならない.
    このロックによって保護された同期コードブロックは原子的に実行され、マルチスレッドはコードブロックを実行しても相互に干渉しない.
    さいにゅう
    内蔵ロックは再読み込み可能であるため、スレッドはすでに独自に保持されているロックを取得することができます.例:
    public class Person{
        public synchronized void doSomething(){
            //···
        }
    }
    public class Student extends Person{
        public synchronized void doSomething(){
            System.out.println("hello");
            super.doSomethin();
        }
    }

    ここで、再読み込み可能であるため、サブクラスは親クラスのsynchronizedメソッドを呼び出すことができ、再読み込みできない場合、このコードはデッドロックを生成します.
    その実装方法の1つは、各ロックにカウント値と所有者スレッドを関連付けることです.カウント値が0の場合、スレッドに持たれていないと考えられます.スレッドが保持されていないロックを要求すると、JVMはロックの所有者をメモし、取得カウント値を1にします.同じスレッドが再び取得されると、カウント値が増加し、スレッドがコードブロックを終了すると、カウンタが減少する.カウント値が0の場合、ロックは解放されます.

    ロックでステータスを保護
    複数のスレッドで同時にアクセス可能な可変状態変数については、同じロックを持つ必要があります.この場合,状態変数はこのロックによって保護されると呼ぶ.
    1つの一般的なロック規則は、すべての可変状態をオブジェクトの内部にカプセル化し、オブジェクトの組み込みロックによってすべてのアクセス可変状態のコードパスを同期させ、そのオブジェクトに同時アクセスが発生しないようにすることです.しかし、この方法は破壊されやすく、すべてのデータがロックされた保護を必要とするわけではありません.
    ある変数がロックによって保護されると、この変数にアクセスするたびにロックを取得する必要があることを意味し、同じ時点で1つのスレッドだけがこの変数にアクセスできることを確保する.複数の変数に関連する場合、各変数は同じロックで保護されなければなりません.

    アクティブ性とパフォーマンス
    同期コードブロックの範囲を合理的に判断することは、同時性を確保し、スレッドのセキュリティを維持することである.さまざまな設計ニーズの間に合理的なバランスを見つける
    長時間の計算を行う場合や、速やかに完了することができない場合は、ロックを持たないでください.

    最後に書く
    何か問題やアドバイスがあれば、交流を歓迎します.