Spring でのシングルトン モードとスレッド セーフの間の矛盾を解決する
この記事の内容は、Spring におけるシングルトン モードとスレッド セーフの矛盾の解決に関するものです。必要な方は参考にしていただければ幸いです。
Spring フレームワークを使用するときに、マルチスレッドの問題を知らない、または無視している人はどのくらいいるでしょうか?
プログラムを作成したり単体テストを実行したりするときに、マルチスレッド テスト環境をシミュレートするのは簡単ではないため、マルチスレッドの問題が発生しにくいからです。複数のスレッドが同じ Bean を呼び出すと、スレッドの安全性の問題が発生します。 Spring の Bean 作成モードが非シングルトンであれば、このような問題は発生しません。
しかし、潜在的な脆弱性を考慮しないと、それらは目に見えないプログラムのキラーとなり、知らない間に発生します。さらに、プログラムが使用のために配布されるときに、実稼働環境でトリガーするのは通常、非常に面倒です。
Spring はスレッド セーフティの問題を解決するために ThreadLocal を使用します。
一般に、Spring では、ほとんどの Bean がシングルトン スコープとして宣言できるのはステートレス Bean のみであることがわかっています。これは、ステートフル Bean は複数のスレッド間で共有できるため、Spring は ThreadLocal を使用して一部の Bean (RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder など) の非スレッドセーフ状態を処理し、スレッドセーフにするためです。
一般的な Web アプリケーションは、プレゼンテーション層、サービス層、永続化層の 3 つのレベルに分かれており、対応するロジックが異なる層に記述され、下位層はインターフェイスを介して上位層への関数呼び出しを開きます。通常の状況では、リクエストの受信から応答を返すまでのすべてのプログラム呼び出しは同じスレッドに属します。
ThreadLocal は、スレッドの安全性の問題を解決するための良いアイデアであり、スレッドごとに変数の独立したコピーを提供することで、変数への同時アクセスの競合を解決します。多くの場合、ThreadLocal は、同期メカニズムを直接使用してスレッド セーフティの問題を解決するよりも簡単で便利であり、結果として得られるプログラムの同時実行性が高くなります。
コードが配置されているプロセスで複数のスレッドが同時に実行されている場合、これらのスレッドがこのコードを同時に実行する可能性があります。各実行の結果がシングルスレッド実行の結果と同じであり、他の変数の値が予想どおり同じである場合、それはスレッドセーフです。言い換えれば、クラスまたはプログラムによって提供されるインターフェイスは、スレッドのアトミックな操作であるか、複数のスレッド間の切り替えによってインターフェイスの実行結果があいまいになることはありません。これは、同期の問題を考慮する必要がないことを意味します。 スレッドの安全性の問題は、グローバル変数と静的変数によって引き起こされます。
各スレッドのグローバル変数と静的変数に対して読み取り操作のみがあり、書き込み操作がない場合、一般に、複数のスレッドが同時に書き込み操作を実行すると、このグローバル変数はスレッドセーフになります。一般に、スレッドの同期を考慮する必要があります。そうしないと、スレッドの安全性が影響を受ける可能性があります。
1) 読み取り操作のみがあるため、定数は常にスレッドセーフです。
2) 各メソッド呼び出しの前に新しいインスタンスを作成すると、共有リソースにアクセスされないため、スレッドセーフになります。
3) ローカル変数はスレッドセーフです。メソッドが実行されるたびに、共有リソースではない別の空間にローカル変数が作成されるためです。ローカル変数には、メソッド パラメーター変数とメソッド内部変数が含まれます。
ステートフルであるということは、データストレージ機能を持つことを意味します。ステートフル オブジェクト (ステートフル Bean) は、データを保存できるインスタンス変数を持つオブジェクトですが、スレッドセーフではありません。メソッド呼び出し間では状態は保持されません。
ステートレスは操作であるため、データを保存できません。ステートレス オブジェクト (Stateless Bean) は、インスタンス変数を持たないオブジェクトであり、データを保存できず、不変クラスであり、スレッドセーフです。
ステートフル オブジェクト:
ステートレス Bean は不変モードに適しており、このテクノロジはシングルトン モードであるため、インスタンスを共有してパフォーマンスを向上させることができます。ステートフル Bean はマルチスレッド環境では安全ではないため、Prototype プロトタイプ モードが適しています。プロトタイプ: Bean に対するリクエストごとに、新しい Bean インスタンスが作成されます。
Struts2 のデフォルトの実装はプロトタイプ モードです。つまり、リクエストごとに新しい Action インスタンスが生成されるため、スレッド セーフティの問題はありません。アクションのライフサイクルが Spring によって管理されている場合、スコープはプロトタイプ スコープ
Thread safety case
SimpleDateFormat (以下、プロトタイプ スコープ) として設定する必要があることに注意してください。 sdf と呼ばれます) 内部クラスには、sdf.parse(dateStr)、sdf.format(date) などの、この sdf に関連する日付情報を格納するために使用される Calendar オブジェクト参照があります。日付関連の文字列。メソッドのパラメータによって渡される日付などはすべてフレンドです。SDF が静的である場合、複数のスレッドがこの SDF を共有すると同時に、この Calendar 参照も共有します。 sdf.parse() メソッドを観察すると、次の呼び出しが見つかります:
Date parse() { calendar.clear(); // 清理calendar ... // 执行一些操作, 设置 calendar 的日期什么的 calendar.getTime(); // 获取calendar的时间 }
ここで発生する問題は、スレッド A が sdf.parse() を呼び出し、calendar.clear() の後で Calendar.getTime() が実行される前に、スレッド B が sdf.parse() を再度呼び出すことです。今度はスレッド B も sdf.clear() メソッドを実行しました。これにより、スレッド A のカレンダー データがクリアされました (実際には A と B が同時にクリアされました)。または、A が clear() を実行した後、スレッド A が一時停止されました。このとき、B は sdf.parse() の呼び出しを開始し、スムーズに終了します。 このように、A のカレンダーに保存されている日付は、後で B が設定したカレンダーの日付になります。その背後に隠された重要な問題 - ステートレス性: ステートレス メソッドの利点の 1 つは、さまざまな環境で安全に呼び出すことができることです。メソッドがステートフルであるかどうかを測定するには、メソッドがグローバル変数やインスタンス フィールドなど、他のものを変更するかどうかによって決まります。 format メソッドは実行プロセス中に SimpleDateFormat のカレンダー フィールドを変更するため、ステートフルです。
これは、システムを開発および設計するときに次の 3 つの点に注意することも思い出させます。
パブリック クラスを自分で作成する場合は、マルチスレッド呼び出しの結果についてコメントする必要があります。明確に説明します
スレッド環境では、各共有変数変数のスレッド セーフに注意を払う必要があります
クラスとメソッドを設計するときは、それらをシームレスなステータスとして設計するよう最善を尽くす必要があります。
解決策1. 必要に応じて新しいインスタンスを作成します:
手順: 必要に応じて SimpleDateFormat を使用します。 新しいインスタンスを作成します。新しいインスタンスを作成する場所で、スレッド セーフティの問題があるオブジェクトを共有からローカル プライベートに変更すると、マルチスレッドの問題を回避できますが、オブジェクト作成の負担も増加します。通常の状況では、パフォーマンスへの影響はあまり明らかではありません。
2. 同期を使用します。SimpleDateFormat オブジェクトを同期します。public class DateSyncUtil {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String formatDate(Date date)throws ParseException{
synchronized(sdf){
return sdf.format(date);
}
}
public static Date parse(String strDate) throws ParseException{
synchronized(sdf){
return sdf.parse(strDate);
}
}
}
public class ConcurrentDateUtil {
private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static Date parse(String dateStr) throws ParseException {
return threadLocal.get().parse(dateStr);
}
public static String format(Date date) {
return threadLocal.get().format(date);
}
}
ThreadLocal<DateFormat>(); public static DateFormat getDateFormat() { DateFormat df = threadLocal.get(); if(df==null){ df = new SimpleDateFormat(date_format); threadLocal.set(df); } return df; } public static String formatDate(Date date) throws ParseException { return getDateFormat().format(date); } public static Date parse(String strDate) throws ParseException { return getDateFormat().parse(strDate); } }
注: ThreadLocal を使用すると、共有変数も排他的になり、スレッドの排他性はメソッドと確実に比較されます。排他性により、同時環境でオブジェクトを作成する際のオーバーヘッドを大幅に削減できます。パフォーマンス要件が比較的高い場合は、通常、この方法をお勧めします。
4. JDK を放棄し、他のライブラリの時刻フォーマット クラスを使用します。Apache コモンズで FastDateFormat を使用し、高速でスレッドセーフな SimpleDateFormat を主張しますが、残念ながらそれは可能です。日付のフォーマットのみを実行し、日付文字列を解析することはできません。
Joda-Time クラス ライブラリを使用して時間関連の問題を処理します。
単純なストレス テストを実行します。方法 1 が最も遅く、方法 3 が最も高速ですが、最も遅い方法でも結果は不十分です。パフォーマンスは悪くありません。一般的なシステムの方法 1 と方法 2 は満たされるため、この時点でシステムのボトルネックになることは困難です。単純な観点からは、方法 1 または方法 2 を使用することをお勧めします。必要に応じて少しパフォーマンスの向上を追求する場合は、キャッシュに ThreadLocal を使用する方法 3 の使用を検討できます。
Joda-Time クラス ライブラリは時間処理に最適なので、使用することをお勧めします。
概要記事の冒頭の質問に戻ります。「どれだけの人が、マルチスレッドの問題を知らないか、無視していることがよくありますか?スプリングフレームワーク?」 》
実際、誰でもコードを書くことができます。なぜアーキテクトが書いたコードの効果はあなたのコードと大きく異なるのでしょうか?あなたが考慮していなかったこのような小さな問題は、建築家が考慮したはずです。
アーキテクトはより幅広い知識を持ち、より具体的な状況を見て、さまざまな問題を解決する豊富な経験を持っています。建築家の考え方や習慣を身につけていれば、建築家には程遠いのでしょうか?
以上がSpring でのシングルトン モードとスレッド セーフの間の矛盾を解決するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。
