2017-12-13 7 views
0

Dateはスレッドセーフではありませんが、これが悪くなる可能性がある場合は実際的な説明が見つかりませんでした。私はDateFormatで解析するとひどく終わりますが、DateJavaで取得する前にDateオブジェクトを複製する必要があります

たとえば、以下のようにDateを使用すると、マルチスレッド環境では何か厄介なことになりますか?

getCreationDateは内部プロパティを返すだけでいいですか?または、Spring/Hibernateがこれを正しく処理しますか?

getCreationDateはどうすればいいですか?

これはなんですか?

@Entity 
public class PostEntity implements Post { 
//... 
    @NotNull 
    @Temporal(value = TemporalType.TIMESTAMP) 
    private Date postDate; 
//... 
    @Override 
    public Date getPostDate() { 
     return postDate; 
    } 
} 

またはこれはもっと類似している必要がありますか?

@Entity 
public class PostEntity implements Post { 
//... 
    @NotNull 
    @Temporal(value = TemporalType.TIMESTAMP) 
    private Date postDate; 
//... 
    @Override 
    public synchronized Date getPostDate() { 
     return new Date(postDate.getTime()); 
    } 
} 
+0

最新の(Java 8)APIを使用していますか? – chrylis

+0

厄介な 'Date'と' DateFormat'は、以前は古くなっていて、何年も前に廃止されました。具体的には、 'Instant'、' OffsetDateTine'、 'ZonedDateTime'、' DateTimeFormatter'です。 –

答えて

3

Java Dateオブジェクトはスレッドセーフではありません。 getPostDate()メソッドを使用して新しいDateを作成する方法は、ほとんどの場合、この問題を回避するために機能します。実際にはベストプラクティスとみなされます。

スレッドの安全性に関係なく、エンティティから返されたときにDateオブジェクトを再作成(複製など)することをお勧めします。 FindBugsはあなたのPOJOで実際にこの問題を探します。その理由は、DateはStringクラスと異なり、変更可能であるためです。

このように、Entity Beanからのライブ参照を返すことで、エンティティ内のDateオブジェクトを、エンティティ内の対応するsetメソッドを使用せずに変更することができます。エンティティは、内部状態が変更されているかどうか、およびデータストアに永続化する必要があるかどうかはわかりません。この種の欠陥は、あなたが認めたいよりも頻繁に起こります。

これはあなたの質問にお答えします。

1

私はそれがDateはスレッドセーフではないことを問題だと聞きましたが、これは悪い終わるかもしれないとき は、任意の実用的な説明を発見していません。

おそらく、あなたの検索に絞り込みすぎている可能性があります。 Dateはスレッドセーフではないため、スレッドセーフでない他の変更可能なクラスと同じコンテキストで同じ問題が発生し、同じ解決策が得られます。

私はDateFormatで解析するとひどく終了したときに知っているが、Date

Dateインスタンスが変更可能です。スレッド間で共有され、適切な外部同期なしに変更された場合、プログラムの動作は明確に定義されていません。一例として、だから、

は、マルチスレッド環境用 厄介な何かで最後まで以下のように日付を使用するのでしょうか? [...]これは行うことができ

を、場合には、再び、それは、異なるスレッドによってアクセスされる同じDateインスタンスを可能にし、それらのスレッドの少なくとも一つは、そのインスタンス化の後に、そのインスタンスを変更する場合。異なるスレッドがDateの値の一貫性のないビューを取得する可能性があります。その結果、アプリケーション全体に波及し、他の不一致が発生する可能性があります。

getCreationDateが内部プロパティを返すだけでいいですか?または Spring/Hibernateがこれを正しく処理しますか?

SpringとHibernateは自動的にこの領域にスレッドの安全性を提供しません。実際には、エンティティ、つまりプロパティの値がスレッド間で共有されるため、エンティティの操作が容易になる場合があります。その程度まで、彼らは問題の一部です。 Hibernate自体はスレッドセーフですが、それだけでは十分ではありません。

getCreationDateはどのように見えるのですか? [...]

あなたのエンティティの実装やあなたのプロパティゲッターで防御的なコピーを採用するかどうか質問しています。防御的なコピーは主に、エンティティ自身のメソッドを使用せずにエンティティの内部状態を変更することを防ぎます。この特定のケースでは、Dateのインスタンスをスレッド間で共有することを最小限に抑えますが、排除することはありません。これらはいくつかの保護を提供しますが、決して完全な解決策ではありません。

が完全にタイプDateのフィールドを持つあなたのエンティティから生じる問題を解消するには、getterとsetterの両方で防御的コピーを実行する必要がある、とあなたはさらにそれらの防御的コピー操作を同期する必要があります。しかし、エンティティ全体を同期させる必要はなく、そのような処理を必要とする複数のプロパティがある場合は、パフォーマンスを向上させる可能性があります。たとえば、

@Entity 
public class PostEntity implements Post { 
//... 
    @NotNull 
    @Temporal(value = TemporalType.TIMESTAMP) 
    private Date postDate = new Date(); 
    private final Object postDateMonitor = new Object(); 
//... 

    @Override 
    public Date getPostDate() { 
     synchronized (postDateMonitor) { 
      return new Date(postDate.getTime()); 
     } 
    } 

    @Override 
    public void setPostDate(Date date) { 
     synchronized (postDateMonitor) { 
      postDate = new Date(date.getTime()); 
     } 
    } 
} 
関連する問題