2010-04-01 5 views
1

J'ai le scénario d'environnement multi-thread suivant - Les demandes arrivent à une méthode et je veux éviter le traitement en double des demandes concurrentes à venir. Comme plusieurs demandes similaires peuvent être en attente d'être traitées dans l'état bloqué. J'ai utilisé la hashtable pour garder une trace de la requête traitée, mais cela va créer des fuites de mémoire, alors comment garder la trace de la requête traitée et éviter les mêmes requêtes à traiter qui peuvent être en état de blocage. Comment vérifier que toute demande entrante en attente/bloquée n'est pas celle traitée dans les threads actuels.Java Multi threading - Éviter le traitement des demandes en double

+0

Je ne comprends pas ce que vous voulez dire. Voulez-vous dire des demandes égales arrivent à plusieurs reprises, mais vous voulez seulement traiter une telle demande une fois? –

+0

oui. disons que les demandes sont différenciées par une clé. il peut y avoir plusieurs demandes pour une clé. Je veux en traiter seulement un. et le reste des demandes d'attente ne devrait pas être traité. Pendant le traitement d'une requête, de nouvelles requêtes peuvent continuer à arriver et attendre, je dois éviter toute demande d'attente de clé. – seawaves

Répondre

1

Si la fuite de mémoire est le problème jetez un oeil à WeakHashMap pour garder votre demande pendant le traitement.

Une autre solution serait d'utiliser un cache mémoire lié ...

+0

J'ai pensé à cela, mais est-il possible de le faire sans utiliser de structure de données. en structurant les contrôles de verrouillage et les vérifications de condition d'une certaine manière – seawaves

+0

De même, nous ne savons jamais quand l'entrée de la carte weakhashmap sera supprimée, si elle a été supprimée avant que toutes les demandes bloquées ne soient traitées, alors le traitement des demandes en double aura lieu. – seawaves

1

D'accord, je pense que je comprends un peu ce que vous voulez.

Vous pouvez utiliser une ConcurrentSkipListSet en tant que file d'attente. Mettre en œuvre vos éléments en file d'attente comme ceci:

class Element implements Comparable<Element> { 
     //To FIFOnize 
     private static final AtomicLong SEQ = new AtomicLong(); 
     private final long id = SEQ.incrementAndGet(); 

     //Can only be executed once. 
     private final Semaphore execPermission = new Semaphore(1); 


     public int compareTo(Element e){ 
      // If element e1 exists on the queue such that 
      // e.compareTo(e1) == 0, that element will not 
      // be placed on the queue. 
      if(this.equals(e)){ 
       return 0; 
      }else{ 
       //This will enforce FIFO. 
       this.id > e.id ? 1 : (this.id < e.id ? -1 : 0); 
      } 
     } 
     //implement both equals and hashCode 

     public boolean tryAcquire(){ 
      return execPermission.tryAcquire(); 
     } 
} 

Maintenant vos fils doivent,

while(!Thread.currentThread().isInterrupted()){ 
    //Iterates from head, therefore simulates FIFO 
    for(Element e : queue){ 
      if(e.tryAcquire()){ 
       execute(e); //synchronous 
       queue.remove(e); 
      } 
    } 
} 

Vous pouvez également utiliser une variante de blocage de cette solution (une SortedSet limitée et laisser les threads de travail bloquer s'il n'y a pas éléments etc.).

1

Il n'y a aucune raison inhérente au fait que le suivi des demandes dans une HashMap (ou de toute autre manière que vous pourriez choisir) conduirait à des fuites de mémoire. Tout ce qui est nécessaire est un moyen de retirer les entrées une fois qu'elles ont été traitées.

Cela pourrait signifier avoir vos threads de traitement de demande:

  • supprimer directement l'entrée;
  • communiquer de nouveau au répartiteur; ou
  • marquer la demande comme traitée, donc que le répartiteur peut supprimer les entrées.
+0

A quelle condition, je devrais nettoyer la hashmap, comment saurai-je qu'il n'y a pas de thread en attente qui ait la même requête que les threads traités. – seawaves

+0

@seawaves: lorsqu'il n'y a pas de thread en attente avec la même requête. Lorsque Dispatcher reçoit une requête pour laquelle un thread est déjà en cours d'exécution, vous allez faire attendre le thread qui le traiterait, n'est-ce pas? Votre répartiteur dispose donc déjà d'un ensemble de requêtes, d'un ensemble de threads en cours d'exécution et d'un ensemble de threads en attente. * ("set" en minuscule - terme mathématique général, pas de structure de données spécifique) *. Ainsi, votre répartiteur, lorsqu'il découvre que le thread en cours d'exécution de la requête X est terminé, vérifie si d'autres threads attendent de fonctionner sur X et les supprime ou démarre l'un des serveurs. – CPerkins