Javaでのスレッドセキュリティの問題

4323 ワード

申し訳ありませんが、国慶節の休暇は私に東西南北を知らないで、リラックスして、とてもリラックスして、もう少しでもっと捨てて、もっと催促する友达に感謝します!
 
更新していませんが、日常の勉強はまだあります.これからはできるだけ共通の知識、非技術を共有します.
 
しかし、今期はこれまでの多前途の話題に復帰しなければならない.スレッドとプロセスの違い、マルチスレッドをどのように実現するか、今日はスレッドのセキュリティ問題について説明しました.
 
まず、単一スレッドにスレッドセキュリティの問題が存在しないため、スレッドセキュリティはデフォルトでマルチスレッド環境にあるという概念を明確にします.スレッドセキュリティは、マルチスレッド環境でプログラムの実行結果と単一スレッドの実行結果と同じである.
 
では、マルチスレッドに神馬問題があるのでしょうか.例を挙げると、次のコードには共有変数countが存在します.プログラムがaddメソッドを呼び出すと、countの値がどれだけあるかは判断できません.それは他のスレッドに何度もaddされているか、addされている可能性があります.
 
public class Obj {
    private int count;

    public int add() {
        return ++count;
    }
}

 
このような状況は断固として許されない.addメソッドが呼び出された回数を計算しない限り.では、同じ時間に共有リソースにアクセスできるスレッドが1つしかないことを保証します.これは、スレッドのセキュリティを実現することです.
 
どのように実現しますか?最も一般的な方法は、ロックと同期です.
 
ロックメカニズムを使用すると、同じ時点でロックが臨界領域に入るスレッドが1つしかないことを保証することができ、ロックとロックの解放の間のこのコードが同じ時点で1つのスレッドでしか実行できないことを保証することができる.
 
public void testLock () {
    lock.lock();
    try{
        int j = i;
        i = j + 1;
    } finally {
        lock.unlock();
    }
}

 
ロックと同様に、同期メソッドまたは同期コードブロックです.非静的同期メソッドを使用する場合、ロックされているのは現在のインスタンスです.静的同期メソッドを使用する場合、ロックされているのはクラスのClassオブジェクトです.静的コードブロックを使用する場合、synchronizedキーワードの後ろの括弧内のオブジェクトがロックされます.
 
public void testLock () {
    synchronized (anyObject){
        int j = i;
        i = j + 1;
    }
}

 
ロックを使用してもsynchronizedを使用しても、本質は同じであり、ロックまたは同期によってリソースの排他性が実現され、実際のターゲットコードセグメントは同じ時間に1つのスレッドでしか実行されず、ターゲットコードセグメントの原子性が保証される.これは性能を犠牲にする代わりに方法です.
 
上記の2つの方法に加えて、例えばキーワードvolatileを使用して共有変数を修飾したり、各ステップの動作の原子性を保証したりする方法もありますが、実際の開発ではスレッドの安全を保証するためにこれらの方法を使用することは推奨されません.
 
では、スレッドの安全を保証することは何なのか見てみましょう.底辺の論理は何なのか.
 
スレッドセキュリティの3つの特性、原子性、可視性、秩序性.
 
原子性:データベースで言う原子性に似ており、分割できない操作です.ここでは,臨界領域コードに対する原子的操作を行い,スレッドの安全を保証する.ロックと同期はいずれも原子性を実現している.
 
≪可視性|Visibility|emdw≫:1つのスレッドが変数を変更すると、すぐにプライマリ・メモリに同期し、他のスレッドにこの変数が変更されたことを知らせます.古いデータは読み込まれません.
 
Javaはvolatileキーワードを提供し、可視性を保証します.volatileを使用して変数を修飾すると、変数の変更がすぐにメモリに更新され、他のスレッドキャッシュで変数のキャッシュが無効に設定されることを保証します.そのため、他のスレッドが値を読み込む必要がある場合は、プライマリメモリから読み込まなければなりません.これにより、最新の値が得られます.
 
秩序性:プログラムの実行順序とコードの作成順序は同じです.これが秩序性ですが、Java仮想マシンは最適化のために、コードの実行順序が文の順序が一致していないとは限りません.これは単一スレッドでは問題なく、JVMが実行結果の正確さを保証します.しかし、マルチスレッドでは問題が発生します.
 
Javaではvolatileによって一定のプログラム上で秩序性を保証することができ、synchronizedとロックによって秩序性を保証することもできる.
 
synchronizedは,ロックが秩序性を保証する原理と原子性を保証するのと同様に,同じ時間に1つのスレッドだけがターゲットコードセグメントを実行することを保証することによって実現される.
 
JVMは実行順序を最適化し、パフォーマンスを向上させる.再ソートメカニズムを設計したが,このメカニズムはマルチスレッドで問題をもたらす可能性があり,この問題を解決するためにコードによって秩序性を保証することができる.これはまだ十分ではありません.JVM自体には、プログラムの実行順序を保証するメカニズムhappens-before(先行実行)があります.残りのコードはJVMがどのようにしたのかによって、性能を向上させることを目的としています.
 
先行実行メカニズムにはいくつかのルールが定義されています.いくつかのルールを出して見学すると、自然なことがこのルールに定義されていると思います.
 
1 volatileによって修飾された書き込み操作は、その後の変数の読み取り操作から生じる.
2スレッド内で、コード順に実行します.
3 Threadオブジェクトのstart()メソッドは、このスレッドの他の動作で先に発生します.
4つのオブジェクト構造がそのfinalizeより先に発生します.
……
 
まとめると、スレッドセキュリティの問題はマルチスレッド環境で共有変数の操作で発生し、データ状態が一致しないことを防止するために、マルチスレッドで変数を共有せず、変数をvolatileに設定し、同期またはロックを使用することができます.実はスレッドの特性が破壊されないことを保証しているのですが...
転載先:https://www.cnblogs.com/YJK923/p/9799589.html