2012-02-19 5 views
3

私はいくつかのスレッドを開始するクラスを持っています。各スレッド(extends Thread)は、クラスWHの新しいインスタンスを呼び出し、クラスWHは、すべてのスレッド間で共有される変数を持ちます。だから、階層は次のようになります。それは、私はちょうど1スレッドをオフに産卵しても立ち往生synchronizedキーワードを使用するとJavaアプリケーションがスタックする

private static volatile Integer size; 

One of the functions tries to access size through Synchronized: 
Synchronized (size) { // Program gets stuck at this line 
... stuff ... 
} 

class S extends Thread { 
.... 
.... 
    WH n = new WH(args); 
.... 
.... 
} 

今クラスWHを共有する変数は、と宣言しています。なぜこれが起こっているのか? (私は私の設計の選択に基づいてのAtomicIntegerを使用したくないFYI-)

おかげ

+1

よく**あなたの**デザインの選択肢は今は動作していません。そして、 'AtomicInteger'はこの正確な使用例のためだけに設計されています。共有状態は正しく実行するのが難しく、他のツールが設計しテストし実証したツールを最大限に活用してください。がんばろう。 –

+1

AtomicIntegerは使用できません。サイズの値を取得し、条件をチェックし、条件に基づいてインクリメントするかどうかを判断する必要があるからです。だから私はそれを可能な限り増やす必要があります。その場合はまだロックが必要です。また、ConcurrentHashMapを使用すると、スタックされてしまいます。 –

+0

'Synchronized'キーワードで別のロックを使用しようとします。たとえば、' WH.class'(別の場所で使用されていない場合)です。 –

答えて

1

はあなたの問題は、非final変数の参照にロックは無用のセマンティクスを持っていることです。

いつでもあなたはsynchronized(var);をやって何かを見てvarは、インスタンスまたは静的変数であるとfinalをマークされていない、何かが一緒に来て、var = new Thing();を行うことができますので、それは、エラーであり、今では、少なくとも2件のスレッドがあります同時にそのブロックで動作しますが、これは例外ではない論理エラーです。コンパイラがこれをキャッチしないという理由だけで、すべてのJavaのlintスタイルのチェッカーはこれを重大なエラーとして通知しますが、それはどんな場合でも有用であるとは限りません。

この場合、不変のIntegerクラスの値を変更して、これらの無駄なセマンティクスを公開しています。

あなたInteger変数sizeは、あなたがあなたのを、それを変更するたびに新しい値を表し、すべてのスレッドが新しい異なるを取得する新しいオブジェクトへの参照を変更しなければならないことを意味する非決勝で、Immutableですロックオンの参照。従ってロックなし

使用して、private static final AtomicInteger size = new AtomicInteger();

をそしてあなたsize以来synchronize(size);は今finalであるあなたの場所にそれを変異させ、目的とすると、正しい意味を得ることができます。

たりすることができsynchronize(some_other_final_reference);と限りで同期され、その参照がfinalあり、それへのハンドルを取得する必要がある任意のスレッドの範囲にすることができ、それが動作するよう定期的にintを使用しています。

私は個人的にはAtomicIntegerを使用しています。これは他のスレッドで変更したくないものをロックしています。条件に基づいて、私はサイズの値を取得する必要があるため、私は、のAtomicIntegerを使用することはできません がそれに状態を確認し、増分またはない

+0

これは、 "なぜ私の' synchronized'キーワードが他のスレッドをブロックしないのでしょうか?これはこの質問の反対です。私はなぜこのコードが壊れているのか分かりませんが、 'valueOf'キャッシングのために同じインスタンスになった' Integer'を他のスレッドがロックしていない限り、単一のスレッドをブロックすることになります。 – yshavit

+0

@yshavit他のすべてのコードを見ることなく、推測だけですが、同期ブロック内の何かか、または 'volatile'キーワードの副作用のためにある種の競合状態が起こっていると思います。その行が最後の実行場所になります。私の合気道センスを言い換えると "並行処理は簡単ですが、正確に並行処理を行うのは難しいです**" ** –

+0

* synchronized(var); varはfinalとマークされていません**、エラーです* ==> **いいえ、それです**。 Javaはあなたがそれをコンパイルすることを許しませんでした。そうでなければ 'RuntimeException'または実際にエラーだった場合は' Error'を投げます。私が同意するのは、それを正当化し、正しいことを行うユースケースを見つけることは困難であるということです。私は、嘘をついて悪い、潜在的に有害な習慣(非最終分野での同期など)を阻止しようとするのは非常に悪いと思っています。それが悪であると言いなさい、それだけで十分であり、誤報を作りません。 –

1

。 だから私はそれを可能な限り増やす必要があります。その場合、まだ私は ロックが必要です。

私はあなたが記述しているものと信じていない、compareAndSet()メソッドを介して、ロックせず、のAtomicIntegerは間違いなく行うことができるものですか?サポートされている唯一のテストは平等ですが、それはあなたのためにはうまくいかないでしょう。

また、変数の同期を計画している場合は、volatileにする必要もありません。

関連する問題