web-dev-qa-db-fra.com

Façon correcte de synchroniser ArrayList dans java

Je ne sais pas si c'est la bonne façon de synchroniser mon ArrayList.

J'ai un ArrayListin_queue qui est transmis depuis la fonction registerInQueue.

ArrayList<Record> in_queue = null;

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

Maintenant j'essaye de le synchroniser. Est-ce la synchronisation de mon in_queue objet 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);
    }
}
34
bob

Vous synchronisez deux fois, ce qui est inutile et ralentit peut-être le code: les changements lors de l'itération sur la liste nécessitent une synchronisation sur toute l'opération, ce que vous faites avec synchronized (in_queue_list) En utilisant Collections.synchronizedList() est superflu dans ce cas (il crée un wrapper qui synchronise les opérations individuelles).

Cependant, puisque vous videz complètement la liste, la suppression itérative du premier élément est la pire façon de le faire, pour chaque élément, tous les éléments suivants doivent être copiés, ce qui en fait une opération O (n ^ 2) - horriblement lent pour les grandes listes.

Au lieu de cela, appelez simplement clear() - aucune itération n'est nécessaire.

Edit: Si vous avez besoin de la synchronisation mono-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 à méthode unique est insuffisante (par exemple, pour toutes les itérations, ou lorsque vous obtenez une valeur, effectuez des calculs en fonction de celle-ci et remplacez-la par le résultat). Dans ce cas, vous devez quand même utiliser la synchronisation manuelle, donc Collections.synchronizedList() est juste une surcharge supplémentaire inutile.

44
Michael Borgwardt

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, afin que les threads puissent écrire dans la file d'attente ou jeter un œil/prendre sans travail de synchronisation supplémentaire de votre part.

8
Brian Agnew

C'est correct et documenté:

http://Java.Sun.com/javase/6/docs/api/Java/util/Collections.html#synchronizedList (Java.util.List)

Cependant, pour effacer la liste, il suffit d'appeler List.clear () .

5
Andrew Duffy

Oui, c'est la bonne façon, mais le bloc synchronisé est requis si vous voulez que tous les suppressions ensemble soient en sécurité - sauf si la file d'attente est vide, aucun retrait n'est autorisé. Je suppose que vous voulez simplement des opérations de file d'attente et de retrait de file d'attente sécurisées, afin que vous puissiez supprimer le bloc synchronisé.

Cependant, il existe des files d'attente simultanées très avancées dans Java telles que ConcurrentLinkedQueue

5
David Rabinowitz

Prenons une liste normale (implémentée par la classe ArrayList) et synchronisons-la. Cela est indiqué dans la classe SynchronizedListExample. Nous transmettons à la méthode Collections.synchronizedList une nouvelle liste de tableaux de chaînes. La méthode renvoie une liste de chaînes synchronisée. // 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 lors de l'itération sur la liste, cet accès est toujours effectué à l'aide d'un bloc synchronisé qui se 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é

1
user4423251