5

ConcurrentHashMap複数のスレッドで使用しても安全であることが保証されている場合finalでも、として宣言する必要があることをどこかで読みましprivate finalた。私の質問は次のとおりです。

1)CocurrentHashMapとして宣言せずにスレッドセーフを維持しますfinalか?

2)プライベートキーワードに関する同じ質問。おそらく、より一般的な質問をする方が良いでしょう -public/privateキーワードは実行時の動作に影響しますか? 内部/外部クラスでの可視性/使用法の意味は理解していますが、マルチスレッドランタイムのコンテキストでの意味はどうですか? コードのようなコードは、実行時ではなくコーディングスタイルの用語でpublic ConcurrentHashMapのみ間違っている可能性があると思いますが、そうですか?

4

2 に答える 2

5

コメントで私が話していたことのより具体的な例を挙げると役立つかもしれません. 私がこのようなことをするとしましょう:

public class CHMHolder {

    private /*non-final*/ CHMHolder instance;

    public static CHMHolder getInstance() {
        if (instance == null) {
            instance = new CHMHolder();
        }
        return instance;
    }

    private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

    public ConcurrentHashMap<String, String> getMap() {
        return map;
    }
}

さて、これはさまざまな理由からスレッドセーフではありません! しかし、threadA が のnull値を認識しinstanceて をインスタンス化しCHMHolder、threadB が偶然にも同じCHMHolderインスタンスを認識したとします (同期がないため、これは保証されません)。threadB は non- を見ていると思いますよnull CHMHolder.mapね?map = new ...threadAと threadB の間に正式な事前発生エッジがないため、そうではない可能性がありreturn mapます。

これが実際に意味することは、ようなものCHMHolder.getInstance().getMap().isEmpty()が をスローする可能性があるということですNullPointerException。これは紛らわしいでしょう — 結局のところ、getInstanceそれは常に non- を返す必要があり、常に non- mapを持つ必要があるようnull CHMHolderに見えます。ああ、マルチスレッドの楽しさ!CHMHoldernull

mapがマークされている場合final、user2864740 が参照した JLS ビットが適用されます。つまり、threadB が threadA と同じインスタンスを認識した場合 (これもそうではない可能性があります)、実行したmap = new...アクションも認識threadAします。つまり、非nullCHM インスタンスを認識します。それが確認されると、CHM の内部スレッドの安全性は、安全なアクセスを確保するのに十分になります。

于 2013-11-07T06:27:39.227 に答える
3

final上記の変数によって名前が付けられたオブジェクトのスレッドセーフ(またはその欠如)については何もprivate言いません。(オブジェクトではなく、変数を変更します。)とにかく..


final フィールドの場合、変数はスレッド間で一貫性があります

コンストラクターが終了すると、オブジェクトは完全に初期化されたと見なされます。オブジェクトが完全に初期化された後にのみオブジェクトへの参照を確認できるスレッドは、そのオブジェクトのfinalフィールドの正しく初期化された値を確認できることが保証されます。

実際のConcurrentHashMap オブジェクトは、それが保証する限り「スレッドセーフ」です。特に、単一のメソッド呼び出し/操作のみが保証されているため、より大きな同期コードを使用する必要がある場合があります.. CHM がそれを作成したオブジェクトからのみアクセスできる場合、これは簡単に制御できます。

を使用することは、他のコードが変数 (およびそれが名前を付けるオブジェクト) にアクセスしてはならないときに「誤って」アクセスするのを防ぐprivateため、通常は良いと見なされます。ただし、プライベート修飾子は修飾子と同じ事前発生保証を確立しないため、スレッドセーフとは直交しています。final

于 2013-11-07T06:00:24.257 に答える