はConcurrentHashMap.get()が保証され、前ConcurrentHashMap.put()により異なるスレッドかどうか

StackOverflow https://stackoverflow.com/questions/1770166

質問

ConcurrentHashMap.get() 保証 詳前 ConcurrentHashMap.put() 異なるスレッドかどうか私の期待をはることはでは、読書のJavaDocsもに、私は99%がこの現実は異なります。私の生産をサーバーに以下の よう する部品が追加されています。(思いつかログイン.)

擬似コードの例:

static final ConcurrentHashMap map = new ConcurrentHashMap();
//sharedLock is key specific.  One map, many keys.  There is a 1:1 
//      relationship between key and Foo instance.
void doSomething(Semaphore sharedLock) {
    boolean haveLock = sharedLock.tryAcquire(3000, MILLISECONDS);

    if (haveLock) {
        log("Have lock: " + threadId);
        Foo foo = map.get("key");
        log("foo=" + foo);

        if (foo == null) {
            log("New foo time! " + threadId);
            foo = new Foo(); //foo is expensive to instance
            map.put("key", foo);

        } else
            log("Found foo:" + threadId);

        log("foo=" + foo);
        sharedLock.release();

    } else
        log("No lock acquired");
} 

ここぞとばかりが起こってます:

Thread 1                          Thread 2
 - request lock                    - request lock
 - have lock                       - blocked waiting for lock
 - get from map, nothing there
 - create new foo
 - place new foo in map
 - logs foo.toString()
 - release lock
 - exit method                     - have lock
                                   - get from map, NOTHING THERE!!! (Why not?)
                                   - create new foo
                                   - place new foo in map
                                   - logs foo.toString()
                                   - release lock
                                   - exit method

なので、私の出力は以下のようなものです:

Have lock: 1    
foo=null
New foo time! 1
foo=foo@cafebabe420
Have lock: 2    
foo=null
New foo time! 2
foo=foo@boof00boo    

第二のスレッドはすぐに入れ!なぜですか?私の生産システムがスレッドだけを表示一部のスレッドの、初の直後にある、スレッドの1、問題です。

った縮小の並行処理レベルConcurrentHashMap(1)にすると、なるべきである。E.g.:

static ConcurrentHashMap map = new ConcurrentHashMap(32, 1);

明日へ向かって走れは間違いだったのか?スマトラ島沖地震が発生。?やはりバグに自分のコード(実際のソフトウェアではなく、上記る希薄化の原因なのでしょうか?私はそれ以上で繰り返し、99%の確んの取り扱いにロックを修正。私はなぜログラムにバグ ConcurrentHashMap または、JVM. 保存するようお願いいたしまうからです。

ゴーリー内容が関連する:

  • クアッドコア64ビットXeon(DL380G5)
  • RHEL4(Linux mysvr 2.6.9-78.0.5.ELsmp #1 SMP ... x86_64 GNU/Linux)
  • Java6(build 1.6.0_07-b06, 64-Bit Server VM (build 10.0-b23, mixed mode))
役に立ちましたか?

解決

いくつかの良い回答をこちらも調査を実施しているのは、同じではないについては実際に提供されず、正確な結果という疑問への答えい:"はConcurrentHashMap.get()が保証され、前ConcurrentHashMap.put()により異なるスレッド".そして無言でいってます。

い:あります。 (項をご参照ください'のメモリの一貫性プロパティ):

アクションには、スレッドの前をオブジェクトより他の同時回収が起こる前に行動後のアクセス又は除去する要素のコレクションから別のスレッド.

他のヒント

この問題を作るのに高価なるオブジェクトの作成、キャッシュに基づく故障データベースのキャッシュが既知の問題です。と幸いことが既に実施されました。

利用できる MapMaker から Google Collecitons.あなただけでコールバック関数を生成するオブジェクトにお、場合にはクライアントコードを見る地図や地図が空のときには、コールバック関数が呼ばれることになり、その結果に入れをまとめたものです。

MapMaker javadocs ...

 ConcurrentMap<Key, Graph> graphs = new MapMaker()
       .concurrencyLevel(32)
       .softKeys()
       .weakValues()
       .expiration(30, TimeUnit.MINUTES)
       .makeComputingMap(
           new Function<Key, Graph>() {
             public Graph apply(Key key) {
               return createExpensiveGraph(key);
             }
           });

ちなみに、オリジナルの例がない利点を利用しConcurrentHashMap、ロック毎にアクセス、なぜならず利用通常のHashMap内鍵でしょうか。

一つのことを考慮するかどうかが鍵が等しい同一ュー内での取得"get"ます。だか Stringsそのあくなってしまうことが問題です。しかしきれな汎用タイプのキーは、省略さ"重要"の擬似コードしていただき、使用している場合は、別のクラスとしてキーとなります。

いずれの場合がありますのまたログのハッシュコードのキーを取得し/ぶしスレッドの1、2.これらが異なると、おの問題です。ることにも注意が key1.equals(key2) がtrueでなければなりません;このんでログインすることができますガイドさんが柔軟に対応し、そのキーにな最終授業で価値があるとロギングを完全修飾クラス名、そのequals()メソッドはこのクラス/授業ができるの鍵と考えられる不平等なのです。

とお答えしタイトル-あConcurrentHashMap.get()を保証動きをタイムリーかつ詳細に前のように、"前"とは、あ が起こる前に はたして二人の関係として指定されたJavaメモリのモデルです。(ConcurrentHashMap特に、ここはだの点に注意が伝えることができるようにさせることができることを第一の場合の両方のスレッド実行時に"正確に同じ時間"の異なるコアを用いただが、あのようにスレッドの2).

場合、スレッドを、価値を兼ハッシュマップその他のスレッドがこの値を取得し、地図が保証された値に挿入される前ます。

この問題が明らかになったに"Javaの並行処理演習"によるジョシュア-Bloch.

引用からテキスト:-

スレッドの安全図書館で所蔵しており、下記の安全に掲載保証がある場合でも、javadocは以下に明らかに

  • をキーまたは値 Hashtable, synchronizedMap または Concurrent-Map 安全に行い、その他のスレッドを取得しまからの地図(かどうかを直接、もしくはiterator);

とは思わない問題なのは"ConcurrentHashMap"ではなくどこかにコード約の推論につ。できないスポットのエラーで上記のコード(∞ps&l∞ps...お久しぶりです。んなに悪ください。).

でもお答え"はConcurrentHashMap.get()が保証され、前ConcurrentHashMap.put()により異なるスレッドかどうか" 私はハッキングと、さまざまな運転条件に対してプログラム。

短: いいえ、ConcurrentHashMapでOK!

ば図書がひどくよう、以下のようなプログラムをshoukd印刷"悪いアクセス!"少なくともいます。ですが100スレッドと100000への通話方法ですが、上記のその版画展"すべてのok!".

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class Test {
    private final static ConcurrentHashMap<String, Test> map = new ConcurrentHashMap<String, Test>();
    private final static Semaphore lock = new Semaphore(1);
    private static int counter = 0;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(100);
        List<Callable<Boolean>> testCalls = new ArrayList<Callable<Boolean>>();
        for (int n = 0; n < 100000; n++)
            testCalls.add(new Callable<Boolean>() {
                @Override
                public Boolean call() throws Exception {
                    doSomething(lock);
                    return true;
                }
            });
        pool.invokeAll(testCalls);
        pool.shutdown();
        pool.awaitTermination(5, TimeUnit.SECONDS);
        System.out.println("All ok!");
    }

    static void doSomething(Semaphore lock) throws InterruptedException {
        boolean haveLock = lock.tryAcquire(3000, TimeUnit.MILLISECONDS);

        if (haveLock) {
            Test foo = map.get("key");
            if (foo == null) {
                foo = new Test();
                map.put("key", new Test());
                if (counter > 0)
                    System.err.println("Bad access!");
                counter++;
            }
            lock.release();
        } else {
            System.err.println("Fail to lock!");
        }
    }
}

更新: putIfAbsent() は論理的に正しいここでは、なかなかできないので問題を回避するためにのみ作成Foo場合にキーがありません。でも、Fooもっていることを確認してくださいそのものをです。David Rousselの答えは良いときはGoogle集依存性にアプリです。


になったかもしれない何かが足りない明らかですが、なぜ警備のセマフォ? ConcurrentHashMap (CHM)ッ算で安全に掲載しており、それはこちら).いることができるように原子"を入れていない場合が"利用chm.putIfAbsent().ることができますcomplciated不変量の地図の内容は変更できませんので、ほとんどの場合を利用する必要が通常のHashMapと同期できます。

お答えをより:一度ご入れを返します、この値に入れた地図が見られる次のスレッドの提示を求められます。

良いモノづくりを行えるだけa+1その他のコメントを、セマフォリリースがあります。

if (sem.tryAcquire(3000, TimeUnit.MILLISECONDS)) {
    try {
        // do stuff while holding permit    
    } finally {
        sem.release();
    }
}

を見て興味深い現のJavaメモリのモデルかどうかを示します。条件はレジスタにフラッシュメモリ?と思うので保証される場合には二つのスレッドの同期オブジェクトと同じオブジェクトその後も一貫したメモリ。

どうなるかはわからないSemphoreは社内でほとんど明らかにないもの同期がいる。

どうなるだ

synchronize(dedicatedLockObject)

く寄せらのセマフォ?

なぜロックを同時にハッシュ地図か?にdef.そのスレッドで安全です。があれば、問題にロックのコードです。そしてスレッドに対して安全パッケージJava のデバッグこれはバリア同期します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top