Est ConcurrentHashMap.get() de la garantie de voir un précédent ConcurrentHashMap.put() par thread différent?

Est ConcurrentHashMap.get() garanti de voir un précédent ConcurrentHashMap.put() par thread différent? Mon espoir est que est, et la lecture de la documentation Javadoc semble l'indiquer, mais je suis à 99% convaincu que la réalité est différente. Sur mon serveur de production ci-dessous semble se produire. (Je l'ai attrapé avec l'exploitation forestière.)

Pseudo-code exemple:

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");
} 

Ce qui semble se passer, c'est ceci:

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

Donc, ma sortie ressemble à ceci:

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

Le deuxième thread ne pas voir immédiatement le mettre! Pourquoi? Sur mon système de production, il y a plus de fils et j'ai seulement vu un thread, le premier qui suit immédiatement le thread 1, ont un problème.

J'ai même essayé de réduire le niveau de simultanéité sur ConcurrentHashMap à 1, non pas qu'il devrait avoir de l'importance. E. g.:

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

Où vais-je tort? Mon attente? Ou est-il un bug dans mon code (le vrai logiciel, pas le ci-dessus) qui en est la cause? J'ai dépassé à plusieurs reprises et je suis sûr à 99% que je suis de la manipulation du verrouillage correctement. Je ne peux même pas imaginer un bug dans ConcurrentHashMap ou de la JVM. Merci de me sauver de moi-même.

Gorey détails qui pourraient être utiles:

  • quad-core 64-bit Xeon (DL380 G5)
  • RHEL4 (Linux mysvr 2.6.9-78.0.5.ELsmp #1 SMP ... x86_64 GNU/Linux)
  • Java 6 (build 1.6.0_07-b06, 64-Bit Server VM (build 10.0-b23, mixed mode))
Votre fonction d'un paramètre appelé "sharedLock" mais vous utilisez un membre appelé "lock" ("sharedLock" n'est pas du tout utilisé). Est-ce intentionnel?
C'est le point où je deviens paranoïaque. En outre, l'enregistrement de la dernière foo droit avant de relâcher le verrou, également vous connecter à la carte.get( "clé" ), et l'identité de code de hachage pour la carte. Sur rapide lu, il est certainement tout a l'air ok et en fait, le verrouillage doit être suffisant si la carte n'est pas modifié par ailleurs. Peut-être il ya quelque chose d'important que de ne pas le faire à travers le dépouillement de la question? <haussement d'épaules>
Un proxy (ou simplement étendre) ConcurrentHashMap et du journal le calendrier et les arguments pour get() et(), ce qui pourrait faire la lumière
Oh, et quand vous écrivez quelque chose, il suffit d'utiliser le Système.err.println (): à noter que c'est le Système.err, pas de Système.; ce dernier est mis en mémoire tampon, l'ancien ne l'est pas.
cela n'a rien à voir avec votre problème, mais je vous conseille fortement de vous mettre la sharedLock.release() appeler à l'intérieur d'un finally bloc. Si une exception se produit entre le tryAcquire et la release appels, le sémaphore sera à la fin fermé pour toujours.

OriginalL'auteur Stu Thompson | 2009-11-20