2016-09-07 5 views
2

ThreadLocalを使用する必要性を理解しようとしています。人々の多くは、ThreadLocalは、スレッドごとにSimpleDateFormatを提供するために使用されるべきだと言いますが、ThreadLocalが使われていないと、どのようにマングルされたSimpleDateFormatが見られるのかは言及していません。私は次のコードを試してみてください、それはちょうどいいと思われる、私はmangledが表示されませんSimpleDateFormat複数のスレッドは、ThreadLocalなしで同じSimpleDateFormatを使用します。

import java.text.SimpleDateFormat; 
import java.util.Date; 

public class ThreadLocalTest { 
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); 
    private static final Date TODAY = new Date(); 
    private static final String expected = "07/09/2016"; 
    public static void main(String[] args) { 
    for (int i = 0; i < 10000; i++) { 
     new Thread(new Runnable() { 
     @Override 
     public void run() { 
      for (int j = 0; j < 1000; j++) { 
      String real = dateFormat.format(TODAY); 
      if (!real.equals(expected)) { 
       throw new RuntimeException("Mangled SimpleDateFormat"); 
      } 
      } 
     } 
     }).start(); 
    } 
    } 
} 

どのように私はThreadLocalを使用していないので、私はNumberFormatExceptionのような例外を生成することができますか?

+1

1000回だけ実行し、同期メソッドである 'println'を使用しました。代わりにそれを永遠に実行し、何も印刷せず、期待される文字列と異なる文字列を取得したときに例外をスローします。 –

+1

'parse'メソッドを使うと例外が簡単に見えます。 – user2018791

答えて

3

重要な点は、SimpleDateFormatの実装がでなく、のスレッドセーフであることです。

これは例外をスローすることを意味しません。 悪い:多分、ときどき共有フォーマッタが間違った出力を与えることがあります。

「マルチスレッドの問題」が例外をうまくスローすると、人々はそれらを恐れずに済みます。何かが間違っていたという直接的なヒントがあるからです。

代わりに、物事が間違っています - 気づかずに

提案:

  1. にテストを強化常にに対してそれを比較することによって、例えば(予想通り日であることを書式設定の結果こと同じ Dateオブジェクト
  2. チェックをフォーマット最初のフォーマット操作の結果)

もちろん、印刷の不一致のみそれが起こったときに通知するようにします。またはそれより良い:ミスマッチであなた自身の例外を投げる!

EDIT:矛盾を強制するために、「より良い」の方法はを解析が、をフォーマットを使用しないことであることが判明!

最後に、別のコメントに対処するために:複数のスレッド間で共有されるオブジェクトに対してのみ矛盾が発生することはもちろんです。各スレッドが自身のフォーマットオブジェクトを持つ場合、共有されていないよりも、したがって問題はない。

+0

私は私のテストを更新しました(私の質問で編集したものを見てください)私は例外を見ることができませんでした。私が 'ThreadLocal'を使用していないために例外が見える場合は、いいでしょう。 – user2018791

+0

私は他に何を言うべきか分からない。あなたが「良い」と思うものは重要ではありません。 Java言語とJVMはそれを行います。我々がそれについて何を考えていても。前述のように、複数のスレッド**が共有オブジェクトを破損した場合、例外はありません。データが破損するだけです。 **スレッド**の間で**共有**の状態になるのは難点**です。あなたや私はそれを変更しません好きではない。 – GhostCat

+0

ありがとうございます。もう一つ質問があります。 'ThreadLocal 'を使った場合と比較して' Thread'を新しくしたときの単純な新しく 'SimpleDateFormat'の違いは何ですか? – user2018791

0

これらのコードを実行するだけで、 "java.lang.NumberFormatException"が表示されます。発生していない場合は、さらに数回

import java.text.ParseException; 
import java.text.SimpleDateFormat; 

public class ThreadLocalDemo1 implements Runnable { 
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 

public static void main(String[] args) { 
    ThreadLocalDemo1 td = new ThreadLocalDemo1(); 
    Thread t1 = new Thread(td, "Thread-1"); 
    Thread t2 = new Thread(td, "Thread-2"); 
    t1.start(); 
    t2.start(); 
} 

@Override 
public void run() { 
    for (int i = 0; i < 100; i++) { 

     System.out.println("Thread run execution started for " + Thread.currentThread().getName()); 
     System.out.println("Date formatter pattern is " + simpleDateFormat.toPattern()); 

     try { 
      System.out.println("Formatted date is " + simpleDateFormat.parse("2013-05-24 06:02:20")); 
     } catch (ParseException pe) { 
      pe.printStackTrace(); 
     } 

     System.out.println("========================================================="); 
    } 
} 

}

0

日付形式はスレッドセーフではありません実行します。

再現できない同じ日にフォーマットすると、2つの異なる日付を使用するか、2番目の日付と異なる秒数の日付を使用する必要があります。日付形式は、日付を設定するフードの下でカレンダーを使用します。最初のスレッドが日付を設定して文字列の書式設定を開始し、異なる日付の別のスレッドが来てそれを同じカレンダーに設定すると、間違った出力が発生します。 SimpleDateFormatが安全それがCalendarオブジェクトを保持している内部calendarフィールドを、持っているということですスレッドされていない方法での

​​
0

ワン:

次のコードは、例外/エラーが発生します。実際に日付をフォーマットする前にSimpleDateFormatが行う最初のことは、同期またはロックなしのthis.calendar.setTime(theDateYouPassedIn)です。これが唯一の方法かどうかはわかりませんが、コードを調べるのはかなり簡単です。

したがって、SimpleDateFormatを失敗させる1つの方法は、異なるスレッドで異なる出力を生成する日付を使用することです。次に例を示します。

public class NotThreadSafe 
{ 
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); 

    public static void main(String[] args) { 
    Date dref = new Date(); 

    // Dates for yesterday and tomorrow 
    Date[] ds = new Date[] { 
     new Date(dref.getTime() - (24L * 60L * 60L * 1000L)), 
     new Date(dref.getTime() + (24L * 60L * 60L * 1000L)) 
    }; 
    String[] refs = new String[ds.length]; 
    for (int i = 0; i < ds.length; ++i) { 
     // How the corresponding ds[i] should be formatted 
     refs[i] = dateFormat.format(ds[i]); 
    } 

    for (int i = 0; i < 100; i++) { 
     // Every even numbered thread uses ds[0] and refs[0], 
     // odd numbered threads use ds[1] and refs[1]. 
     int index = (i % 2); 
     final Date d = ds[index]; 
     final String ref = refs[index]; 
     new Thread(new Runnable() { 
     @Override 
     public void run() { 
      while (true) { 
      String s = dateFormat.format(d); 
      if (!ref.equals(s)) { 
       throw new IllegalStateException("Expected: " + ref + ", got: " + s); 
      } 
      } 
     } 
     }).start(); 
    } 
    } 
} 

コメントが示すように、すべての偶数番号のスレッドが昨日の日付をフォーマットし、奇数のスレッドが明日の日付を使用します。

これを実行すると、ほとんどの場合、すべての書式が同じ日付になるまで、スレッドは例外をスローして自殺を開始します。

関連する問題