2009-08-29 13 views
5

は、次のコードを考える:変数のスレッドセーフな設定(Java)?

public class FooBar { 

public static volatile ConcurrentHashMap myConfigData = new ConcurrentHashMap();  

} 

public class UpdaterThread implements Runnable { 

run { 

//Query the Data from the DB and Update the FooBar config Data 
FooBar.myConfigData = ConfigDataDAO.getLatestConfigFromDB(); 
} 
} 

スレッド-Classは、定期的にmyConfigData Membervariableを更新します(エグゼ5分ごと経由)。 「外部」スレッドのスレッドセーフ(アトミック)のmyConfigDataの設定ですか、またはすべての読み取りおよび書き込み操作をmyConfigData変数に同期させる必要がありますか?

EDIT:ConcurrentHashMapはスレッドセーフであるかどうか(javadocに準拠しています)ではなく、myConfigDataメンバー変数にConcurrentHashMap自体を設定するかどうかという問題です。この変数は、いくつかのスレッドによって "一度に"読み書きされるので、設定がアトミックかどうかということになります。私はこれが "Java参照変数の設定はアトミックかどうか"に一般化できると思います。

(。。私もこれは別の問題であると不可分とは何の関係もありません、それは揮発性行わ - 私の質問は - ではなく、「他のスレッドでの視認性」と事前発生関係)

答えて

12

参考文献を置き換えることは安全です。 Java language Specificationを参照してください:

スレッドが変数の値を使用する場合、取得する値は実際にそのスレッドまたは他のスレッドによって変数に格納された値です。これは、プログラムに適切な同期のためのコードが含まれていなくても当てはまります。たとえば、2つのスレッドが異なるオブジェクトへの参照を同じ参照値に格納する場合、変数には後であるオブジェクトまたは他のオブジェクトへの参照が含まれ、他のオブジェクトへの参照や破損した参照値は参照されません。 (longとdoubleの値のための特別な例外があり、§17.4を参照してください。)

+3

@unknown:引用されたテキストはあなたの言うことを言っていません!!実際のところ、JLSの次の箇条書きは次のとおりです。「明示的な同期がない場合、インプリメンテーションは主メモリを任意の順序で更新することができます。驚きを避けるプログラマは明示的な同期を使用する必要があります。 " –

+1

@unknown:OPのコードが安全である唯一の理由は、彼が変数を「volatile」と宣言したことだけです。 –

+3

@Stephen 質問の主なポイントは割り当てのアトミック性に関するものだと思います。だから私はこの仕様の部分を引用した。 私が正しく理解していれば、このアトミック性は、volatileが使われなくても保証されます。 しかし、他のスレッドでは変数の更新が表示されず、「古い」参照が引き続き表示されることがあります。しかし、スレッドは "他のオブジェクトへの参照または破損した参照値"を決して参照しません。 – Wolfgang

0

ConcurrentHashMpは以下のとおりです。

検索の完全な並行性と更新のための予測可能な並行性をサポートするハッシュテーブル。このクラスは、Hashtableと同じ機能仕様に従い、Hashtableの各メソッドに対応するメソッドのバージョンを含みます。ただし、すべての操作がスレッドセーフであっても、検索操作ではロックが必要なく、すべてのアクセスを妨げるようにテーブル全体をロックするためのサポートはありません。このクラスは、スレッドの安全性に依存するが同期の詳細に依存しないプログラムでは、Hashtableと完全に相互運用可能です。

javadocsはスレッドセーフであると言います。

構成を設定するには、多くの作業とCPUサイクルが必要です。それは本当にこのダイナミックですか?あるいは、あなたは月に一度交換して、あなたがするときにサービスがバウンスするだけですか?

+0

あなたの答えをありがとう!私は私の質問をより明確にし、私の質問を編集しようとしました。 –

0

は、更新によって、あなたがConcurrentHashMapの内部のエントリを上書きする意味場合:

FooBar.myConfigData.put(somekey, somevalue); 

そして、それはよう、スレッドセーフ間違いですダフィモは言った。

あなたが新しい値でmyConfigData変数を上書きする場合:

FooBar.myConfigData = new ConcurrentHashMap(); 

あなたは正しく揮発性として変数をラベル付けしているとしてそれは、また、スレッドセーフです。 volatileキーワードは、複数のスレッドが同じ変数に安全かつアトミックにアクセスできることを意味します。

EDIT:質問はありません。ConcurrentHashMapはスレッドセーフです(javadocに準拠しています)。myConfigDataメンバー変数にConcurrentHashMap自体を設定します。この変数は、複数のスレッドによって「一度に」読み書きされるので、設定がアトミックであるかどうかにかかわらず問題になります。私はこれが一般化できると思う、Java Reference変数の設定がアトミックかどうか。

(これはまた別の問題であり、原子性(私の質問)ではなく「他のスレッドでの可視性」と関係の前に起こる)とは関係ありません。

実は「揮発性」はアトミックためで、何もパブリック変数は、常に任意のスレッドに表示されます、視界に影響を与えません。

+0

あなたの答えもありがとう! –

2

volatileは、少なくともJava 5以来、原子不可能性、可視性を保証し、「メモリバリア」(Googleがその意味を知りたい場合はgoogle)として機能します。 したがって、これはまさにあなたが望むものです。

0

確信が持てない場合は、いつでもAtomicReferenceを使用できます。

私はあなたの場合は揮発性で十分だと思いますが。

関連する問題