ホームページ  >  記事  >  Java  >  Java のどのクラスがスレッドセーフですか?

Java のどのクラスがスレッドセーフですか?

(*-*)浩
(*-*)浩オリジナル
2019-05-21 13:36:398055ブラウズ

スレッドセーフなコードを記述するためには、状態アクセス操作、特に共有状態や変更可能な状態へのアクセスを管理することが中心となります。複数のスレッドが状態変数にアクセスし、1 つのスレッドが書き込み操作を実行する場合、同期メカニズムを使用して、これらのスレッドの変数へのアクセスを調整する必要があります。ステートレス オブジェクトはスレッドセーフである必要があります。

Java のどのクラスがスレッドセーフですか?

#ステートレス オブジェクトにステートを追加するとどうなるでしょうか?

次の方法でリクエストの数を管理するために、サーブレットに「ヒット カウンター」を追加するとします。サーブレットにlong 型フィールドを追加し、リクエストが発生するたびにこの値に 1 を加えます。処理されます。

public class UnsafeCountingFactorizer implements Servlet {
     private long count = 0;
 
     public long getCount() {
            return count ;
     }
 
     @Override
     public void service(ServletRequest arg0, ServletResponse arg1)
                 throws ServletException, IOException {
            // do something
           count++;
     }
}
残念ながら、count はアトミックな操作ではないため、上記のコードはスレッドセーフではありません。実際には、count の値を読み取る、値に 1 を加える、そして計算という 3 つの別々の操作が含まれています。結果は count に書き込まれます。スレッド A がカウントが 10 であることを読み取ると、スレッド B はすぐにカウントが 10 であることを読み取ります。スレッド A は 1 を追加して 11 に書き込みます。スレッド B はすでにカウントが 10 であることを読み取っているため、1 を追加して書き込んだ後でも、カウントは 11 のままです。したがって、カウントは失われます。

同時実行プログラミングにおいて、このような実行タイミングの誤りによる不正な結果は非常に重要な状況であり、正式名称は「競合状態」です。最も一般的なタイプの競合状態は、「最初にチェックしてから実行する」操作です。つまり、無効な可能性のある観察結果が次の操作を決定するために使用されます。

初期化の遅延は、一般的な状況です。競合状態:

public class LazyInitRace {
     private SomeObject instance = null;
     public SomeObject getInstance() {
            if(instance == null)
                 instance = new SomeObject();
            return instance ;
     }
}
LazyInitRace の競合状態が含まれます。まず、スレッド A がインスタンスが null であると判断し、次にスレッド B がインスタンスも null であると判断し、スレッド A とスレッド B がそれぞれオブジェクトを作成します。初期化中にエラーが発生しました。

静的状態を回避するには、スレッドが変数を変更するときに、他のスレッドがこの変数を何らかの方法で使用できないようにする必要があります。これにより、他のスレッドは変更の前後の状態のみを読み取り、変更できるようになります。状態を変更する過程ではなく、操作が完了しました。

UnsafeCountingFactorizer の例では、スレッドが安全でない理由は、カウントがアトミックな操作ではないためです。アトミック クラスを使用すると、加算操作がアトミックであることを確認できます。
##

 public class CountingFactorizer implements Servlet {
     private final AtomicLong count = new AtomicLong(0);
 
    public long getCount() {
          return count .get() ;
   }
 
    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
               throws ServletException, IOException {
          // do something
          count.incrementAndGet();
   }
}
AtomicLong は java.util.concurrent.atomic パッケージのアトミック変数クラスで、アトミックな自己インクリメント操作を実装できるため、スレッドセーフです。安全。

関連する学習の推奨事項:

Java 基本チュートリアル

以上がJava のどのクラスがスレッドセーフですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。