2017-08-03 3 views
0
ConcurrentHashMap<Long, CopyOnWriteArrayList<Observation> 
mostRecentObservationDB = new ConcurrentHashMap<Long, 
    CopyOnWriteArrayList<Observation>(524288, 0.75f, 32); 

Ceci est ma carte. J'essaye de lire et d'écrire avec plusieurs threads en même temps, mais d'une façon ou d'une autre il crée toujours plusieurs clés. Seperate Thread, qui filtre cette table de hachage en supprimant les clés de plus de 10 secondes.Les threads mulitples essayent d'écrire en millisecondes comme clé, mais au lieu d'une clé, beaucoup de clés sont créées dans ConcurrentHashMap

while (true) { 
    try { 
     Thread.sleep(4000); 
     if(/*Time (key) older than 10 seconds*/) { 
      mostRecentObservationDB.remove(key); 
     } 

    } catch (Exception e) { 

    } 
} 

Le problème est qu'après avoir supprimé la clé, il crée plusieurs clés lors de l'initialisation. Ce sont mes journaux.

key -> 1501779153776, value 
key -> 1501779153826, value 
key -> 1501779153876, value 
key -> 1501779153896, value 

Je veux qu'ils soient stockés comme une seule clé lors de la suppression de l'opération. C'est comme ça que ça devrait être stocké.

key -> 1501779153776, value 

Cependant, quand je lis de lui et puis supprimer toutes les entrées par remove() méthode, je veux qu'aucun autre thread écrit à la carte pendant que je suis en train de lire le contenu de carte et de les supprimer.


C'est le code qui comporte étrange:

public static void main(String[] args) { 
    ConcurrentHashMap<Long, String> tenSecondBucket = 
     new ConcurrentHashMap<Long, String>(); 

    Thread writingThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      while (true) { 
       try { 
        Thread.sleep(1); 

        if(tenSecondBucket.size() > 0) { 
         // getting last key 
         long lastKey = 0; 
         for (long keyValue : tenSecondBucket.keySet()) { 
          lastKey = keyValue; 
         } 

         if(System.currentTimeMillis() - lastKey > 10000) { 
          tenSecondBucket.put(System.currentTimeMillis(), "secondEntry"); 
         } else { 
          tenSecondBucket.put(lastKey, "updatedEntry"); 
         } 
        } else { 
         tenSecondBucket.put(System.currentTimeMillis(), "newEntry"); 
        } 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }); 

    writingThread.start(); 

    Thread removingThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      while (true) { 
       try { 
        Thread.sleep(4000); 

        if(tenSecondBucket.size() > 0) { 
         tenSecondBucket.keySet().stream().forEach(key -> { 
          if(System.currentTimeMillis() - key > 10000) { 
           tenSecondBucket.remove(key); 
          } 
         }); 
        } 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }); 

    removingThread.start(); 

    Thread readingThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      while (true) { 
       try { 
        Thread.sleep(4000); 

        if(tenSecondBucket.size() > 0) { 
         tenSecondBucket.keySet().stream().forEach(key -> { 
          System.out.println("testing key which is timestamp " + key); 
         }); 
        } 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }); 

    readingThread.start(); 
} 
+0

Vous pouvez utiliser [l'opérateur de diamant] (https://stackoverflow.com/questions/4166966/what-is-the-point-of-the-diamond-operator-in-java-7) pour raccourcir significativement cette déclaration, comme vous le faites pour 'initializingObservation'. – Michael

+4

Pouvez-vous fournir un [mcve]? Vous n'avez montré que la partie de votre code qui ajoutera (supposément) une nouvelle entrée toutes les 10 secondes - en fonction de ce code, on s'attendrait à voir plusieurs clés dans votre carte ... – assylias

+0

@assylias J'espère que vous comprenez avec cette explication . Le problème est lors de la suppression de la clé, qui est plus de 10 secondes, les autres threads viennent et vérifie et pense qu'il n'y a pas d'entrée et essayer de créer une nouvelle entrée en même temps. Donc, à la fin, j'ai plusieurs clés et les valeurs séparées par des clés multiples inutiles au lieu d'une clé. Mon but est de capturer toutes les 10 secondes quelques observations en comparant leur valeur temporelle. –

Répondre

1

Le problème est la façon dont vous dérivez le "lastKey". Vous semblez avoir besoin de la valeur de temps la plus élevée présente dans la carte, et vous supposez que ce serait la dernière entrée, la tenSecondBucket.keySet(). Cependant, la méthode keySet() renvoie un ensemble, qui par nature n'est pas ordonné (dans tous les cas, les cartes ne permettent pas de maintenir une liste ordonnée des clés)

Vous devez remplacer ce code-

long lastKey = 0; 
for (long keyValue : tenSecondBucket.keySet()) { 
    lastKey = keyValue; 
} 

avec ce code -

long lastKey = 0; 
for (long keyValue : tenSecondBucket.keySet()) { 
    lastKey = keyValue > lastKey? keyValue : lastKey; 
} 

Après ce changement, le code fonctionne bien
Notez bien que le code ne encore de la place pour l'amélioration/refactoring