2009-09-16 7 views
31

Je ne sais pas si c'est la bonne façon de synchroniser mon ArrayList. J'ai un ArrayListin_queue qui est passé de la fonction registerInQueue.Correct façon de synchroniser ArrayList dans Java

ArrayList<Record> in_queue = null; 

public void registerInQueue(ArrayList in_queue) 
{ 
    this.in_queue = in_queue; 
} 

Maintenant j'essaye de le synchroniser. Synchronise-t-il mon objet in_queue correctement?

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 

synchronized (in_queue_list) { 
    while (in_queue_list.size() > 0) { 
     in_queue_list.remove(0); 
    } 
} 
+5

Vous ne pouvez pas vraiment mettre à niveau une liste à synchroniser car une référence vous est transmise, vous ne la possédez donc pas réellement. Tout ce qui vous a donné la référence pourrait encore modifier la liste originale qui vous a été transmise simultanément. Indépendamment de la synchronisation que vous ajoutez, à moins que l'on sache explicitement que la liste sera protégée par son verrou intrinsèque. –

+0

Je vais mettre un bloc synchronisé autour de toute opération dans la file d'attente. Merci! – bob

Répondre

41

vous synchronisez deux fois, ce qui est inutile et peut-être ralentit le code: modifications en itérer sur la liste ont besoin d'un synchronnization sur l'opération , que vous faites avec synchronized (in_queue_list) L'utilisation de Collections.synchronizedList() est superflue dans ce cas (il crée un wrapper qui synchronise les opérations individuelles).

Cependant, puisque vous videz complètement la liste, la suppression répétée du premier élément est la pire des façons possibles, pour chaque élément, tous les éléments suivants doivent être copiés, ce qui en fait un O (n^2) opération - horriblement lent pour les plus grandes listes.

Appelez simplement clear() - aucune itération n'est nécessaire.

Edit: Si vous avez besoin de la synchronisation unique méthode de Collections.synchronizedList() plus tard, alors c'est la bonne façon:

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 
in_queue_list.clear(); // synchronized implicitly, 

Mais dans de nombreux cas, la synchronisation unique méthode est insuffisante (par exemple pour toute itération, ou quand vous obtenez une valeur, faites des calculs basés dessus et remplacez-le par le résultat). Dans ce cas, vous devez utiliser la synchronisation manuelle de toute façon, donc Collections.synchronizedList() est juste inutile.

+7

Synchroniser deux fois ici n'est pas inutile: il assure que pendant que la boucle est en cours d'exécution, personne d'autre ne peut modifier la liste. Cependant, ne pas utiliser 'clear()' est un peu exagéré. :) – Bombe

+0

donc je devrais faire quelque chose comme: synchronized ((List) in_queue)? – bob

+0

Ok! J'ai effectivement enlevé un peu de code pour le rendre simple. Je n'aurai pas de problème avec clear()/remove(). merci =] – bob

5

Oui, c'est la bonne façon, mais le bloc synchronisé est requis si vous voulez que toutes les suppressions soient sécurisées - à moins que la file d'attente ne soit vide, aucune suppression n'est permise. Ma conjecture est que vous voulez juste des opérations sûres de queue et de dequeue, ainsi vous pouvez enlever le bloc synchronisé.

Cependant, il y a beaucoup des files d'attente concurrentes avancées en Java telles que ConcurrentLinkedQueue

8

En regardant votre exemple, je pense que ArrayBlockingQueue (ou ses frères et sœurs) peut être utile. Ils s'occupent de la synchronisation pour vous, ainsi les threads peuvent écrire dans la file d'attente ou peek/take sans travail de synchronisation supplémentaire de votre part.

+0

Merci pour la suggestion! C'est ce que j'essaie de faire, je ne suis pas sûr de limiter la taille de mon tableau si. Je vais garder cela à l'esprit. ;) – bob

+0

Notez qu'il existe également une LinkedBlockingQueue. Et vous n'avez pas nécessairement besoin d'imposer des limites. –

+0

merci, je m'en souviendrai =] – bob

1

Prenons une liste normale (implémentée par la classe ArrayList) et la rendons synchronisée. Ceci est montré dans la classe SynchronizedListExample. Nous transmettons à la méthode Collections.synchronizedList une nouvelle ArrayList de chaînes. La méthode renvoie une liste synchronisée de chaînes. // Voici la classe SynchronizedArrayList

package com.mnas.technology.automation.utility; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.List; 
import org.apache.log4j.Logger; 
/** 
* 
* @author manoj.kumar 
* @email [email protected] 
* 
*/ 
public class SynchronizedArrayList { 
    static Logger log = Logger.getLogger(SynchronizedArrayList.class.getName()); 
    public static void main(String[] args) {  
     List<String> synchronizedList = Collections.synchronizedList(new ArrayList<String>()); 
     synchronizedList.add("Aditya"); 
     synchronizedList.add("Siddharth"); 
     synchronizedList.add("Manoj"); 
     // when iterating over a synchronized list, we need to synchronize access to the synchronized list 
     synchronized (synchronizedList) { 
      Iterator<String> iterator = synchronizedList.iterator(); 
      while (iterator.hasNext()) { 
       log.info("Synchronized Array List Items: " + iterator.next()); 
      } 
     }  
    } 
} 

Notez que lorsque vous parcourez la liste, cet accès est toujours fait à l'aide d'un bloc synchronisé qui verrouille sur l'objet synchronizedList. En général, l'itération sur une collection synchronisée doit être effectuée dans un bloc synchronisé.

Questions connexes