https://www.cnblogs.com/zemliu/p/3290585.html
https://www.cnblogs.com/peida/archive/2013/05/31/3070790.html
1.原因
SimpleDateFormat(以下、SDF)カレンダーオブジェクト・クラスは、入力日付文字列に関連するメソッドのパラメータのようなSDFおよび関連する日付情報、例えばsdf.parse(関数datestr)、sdf.format(日付)を格納するために使用される内部基準を有します、日付など、これはあなたの自衛隊が静的である場合、これは、複数の自衛隊のスレッド間で共有される問題が発生するだけでなく、カレンダーの参照を共有します。友だちのカレンダーを参照するに格納されており、観測sdf.parse()メソッドは、次の呼び出しがあります:
解析DATE(){ calendar.clear(); //クリーンアップカレンダー ... //いくつかの操作日時を行う、カレンダーがどのよう設けられている calendar.getTime(); //はタイムカレンダーを取得 }
これは問題を引き起こす可能性がある場合、スレッドAはsdf.parse()を呼び出した場合、であり、そしてcalendar.clear()がcalendar.getTime()を実行していないし、スレッドBは、)(sdf.parseを呼び出しますスレッドBは、また、()メソッドをsdf.clear実行されると、このように)場合((、Bが同時にクリアされ、実際に)カレンダーデータが空になるスレッド。または実行calendar.clearにつながりますそしてB後日カレンダーの設定に、Bは(sdf.parseを呼び出す開始今回懸濁)とスムーズIを終了、日付がカレンダーでこれを格納されています
問題を再現するために2
輸入java.text.ParseException。 輸入java.text.SimpleDateFormatの。 輸入java.util.Date; 輸入java.util.concurrent.ExecutorService。 輸入java.util.concurrent.Executors。 輸入java.util.concurrent.TimeUnit。 / ** * @author zhenwei.liu 13-8-29下午5:35 2013で作成した * @versionの$ Idをする$ * / publicクラスDateFormatTestはスレッド{拡張 プライベート静的のSimpleDateFormat自衛隊=新しいてSimpleDateFormat( "YYYY-MM-DD"を); プライベート文字列名; プライベート文字列関数datestr。 プライベートブール睡眠。 公共DateFormatTest(文字列名、文字列関数datestr、ブール睡眠){ this.name =名。 this.dateStr = datestrを。 this.sleep =睡眠。 } @Override 公共ボイドラン(){ 日付= NULL; (スリープ)の場合{ {しようと TimeUnit.MILLISECONDS.sleep(2000); }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } } {試みる 日付= sdf.parse(関数datestr)を、 }キャッチ(はParseException電子){ e.printStackTrace(); } のSystem.out.println(名+ ":日付:" +日付)。 } 公共の静的な無効メイン(文字列[]引数)例外:InterruptedExceptionをスロー{ ExecutorServiceのエグゼキュータ= Executors.newCachedThreadPool(); (sdf.parse開始)2S SLEEP後に意志を// てexecutor.execute(新新DateFormatTestをtrueに( "A"、 "1991年9月13日"、)); //はBを再生ブレークポイントを、この方法は、途中で立ち往生され てexecutor.execute(新しい新しいDateFormatTest( "B"、 "2013年9月13日"、偽に)); executor.shutdown(); } }
sdf.parseにブレークポイントで、このコードのデバッグモードの実行を使用し、マーク()メソッドで
パース(){ calendar.clear() ブレークポイントをヒット//ここ calendar.getTime() }
プロセス:
アップを実行した後、1)最初のスレッドがスリープ状態に入ります
2)Bのスレッドがブレークポイントでカードを実行します
3)スレッドウェイクアップ、実行calendar.clear()、日付が1991年9月13日sdf.calendar設定され、この時のカレンダーはAB 1991年9月13日です
4)ブレークポイントは、次の出力を続けましょう
:日付:9月13日(金)0時00分○○秒CDT 1991
B:日付:9月13日(金)0時00分○○秒CDT 1991
これは、我々は結果を期待するものではありません
3.ソリューション
それぞれの新しいスレッドがスレッド安全性の問題を避けるために、独自の自衛隊例を有するように、最も簡単な解決策は、私たちは、静的を取り除くことができます
ただし、高い同時実行の場合には、このメソッドを使用すると、新たな自衛隊の多くなると自衛隊を破壊し、これは非常にリソースを大量に消費することができます
次のように同時要求の場合、サイトに関するタスクとスレッドの実装が理解できます
このようなTomcatのスレッドプールは4である最大数のスレッドとして、あなたは今、1000(1,000人のユーザーがあなたのウェブサイトの機能を指す有すると理解)しているタスクを実行する必要があり、
この1000年の使命は、我々が書き込み処理クラスの日付関数で使用されます
あなたが新しいのSimpleDateFormatを使用する方法を処理などの日付関数を言うならA)、これは1000自衛隊の作成と破棄されます
B)は、JavaのThreadLocalのソリューションを提供するために、それが動作する方法は、各スレッドがインスタンスを1つだけになるということです、それは我々が1000年のミッションの実装、自衛隊の唯一の4つのインスタンスの合計を終えたと言うことです。
単一のスレッドは間違いなく、このようなスレッド#1などのタスクの順序は、タスク#1〜#250の実装を担当しているので、また、それは、複数の並行スレッドを発行することはありません、その後、彼は順次タスク#1〜#250を実行します
スレッド#2は、自身の自衛隊のインスタンスを持って、彼はそうでもタスクのタスク#251-#500の順で、
III。ソリューション
1.必要な時間の新しいインスタンスを作成します。
パッケージcom.peidasoft.dateformat。 輸入java.text.ParseException。 輸入java.text.SimpleDateFormatの。 輸入java.util.Date; パブリッククラスDateUtil { 公共の文字列は、FormatDate(日付)にはParseException {スロー静的 てSimpleDateFormatのSDF =新しいてSimpleDateFormatを( "YYYY-MM-DD HH:MM:SS")。 sdf.format(日付)を返します。 } パブリック静的日付解析(文字列strDateは)はParseException {スロー のSimpleDateFormat SDF =新しいてSimpleDateFormatを( "YYYY-MM-DD HH:MM:SS")。 sdf.parse(strDate)を返します。 } }
説明:それは必要とされる場所のSimpleDateFormatの新しいインスタンスを作成しますが使用されている、関係なく、地元の民間への共有オブジェクトによってスレッド安全性の問題があるだろう何時間、マルチスレッドの問題を回避しない、だけでなく、オブジェクトを作成する負担が増加することができます。一般的に、これは実際に性能比に非常に大きな影響はありません。
2.同期:同期オブジェクトのSimpleDateFormat
パッケージcom.peidasoft.dateformat。 輸入java.text.ParseException。 輸入java.text.SimpleDateFormatの。 輸入java.util.Date; パブリッククラスDateSyncUtil { プライベート静的のSimpleDateFormat自衛隊=新しいてSimpleDateFormat( "YYYY-MM-DD HH:MM:SS"); 公共の静的な文字列は、FormatDate(日付)にはParseException {スロー 同期(SDF){ 戻りsdf.format(日付)。 } } パブリック静的日付解析(文字列strDateは)はParseException {スロー 同期(SDF){ 戻りsdf.parse(strDate)を、 } } }
説明:スレッドがこのメソッドを呼び出したときに、多くのスレッドがあり、他のスレッドは、このメソッドは、パフォーマンス上の時間のある程度のマルチスレッド大量に、ブロックします呼び出したいです。
3. ThreadLocalの:
パッケージcom.peidasoft.dateformat。 輸入java.text.DateFormatの。 輸入java.text.ParseException。 輸入java.text.SimpleDateFormatの。 輸入java.util.Date; パブリッククラスConcurrentDateUtil { プライベート静的にThreadLocal <たDateFormat> THREADLOCAL =新規のThreadLocal <たDateFormat>(){ @Overrideが たDateFormatはinitialValue(保護){ ( "YYYY-MM-DD HH:MM:SS")新しいてSimpleDateFormatを返します。 } }。 パブリック静的日付解析(文字列関数datestrは)はParseException {スロー リターンthreadLocal.getは()(関数datestr)を解析します。 } パブリック静的文字列の形式(日付){ threadLocal.get()形式(日付)を返します。 } }
書くための別の方法:
パッケージcom.peidasoft.dateformat。 輸入java.text.DateFormatの。 輸入java.text.ParseException。 輸入java.text.SimpleDateFormatの。 輸入java.util.Date; パブリッククラスThreadLocalDateUtil { プライベート静的最終的な文字列DATE_FORMAT = "YYYY-MM-DD HH:MM:SS"。 プライベート静的にThreadLocal <DateFormatの> THREADLOCAL =新しいのThreadLocal <DateFormatの>(); パブリック静的にDateFormatてgetDateFormat() { たDateFormat DF = threadLocal.get()。 IF(DF == NULL){ DF =新しいてSimpleDateFormat(DATE_FORMAT)。 threadLocal.set(DF)。 } DFを返します。 } 公共の静的な文字列は、FormatDate(日付)にはParseExceptionを{スロー てgetDateFormat()形式(日付)を返します。 } パブリック静的日付解析(文字列strDateは)はParseException {スロー リターンてgetDateFormatを()(strDate)を解析します。 } }
説明:使用ThreadLocalをするだけでなく、共有変数が排他的になり、同時実行環境よりも排他的なスレッド確かに排他的な方法は、オブジェクトを作成するオーバーヘッドの多くを減らすことができます。性能要件に比較的高い場合、一般的に、このメソッドを使用することをお勧めします。
ここで、マルチスレッドSDFの問題を解決するTHREADLOCAL用いた例であります