2017-06-19 4 views
1

J'utiliseEn utilisant synchronizedList avec boucle et ajouter des éléments à l'intérieur il

Collections.synchronizedList(new ArrayList<T>()) 

partie du code est:

list = Collections.synchronizedList(new ArrayList<T>()); 

public void add(T arg) { 
    int i; 
    synchronized (list) { 
     for (i = 0; i < list.size(); i++) { 
      T arg2 = list.get(i); 

      if (arg2.compareTo(arg) < 0) { 
       list.add(i, arg); 
       break; 
      } 

     } 

Est-il vrai que pour la boucle est réellement en utilisant iterator et donc doit envelopper le pour avec synchronisé?

Est-il thread-sûr à utiliser synchronisé et ajouter à l'intérieur comme je l'ai fait ici? Je suis désolé si ces questions sont très basiques, je suis nouveau sur le sujet et je n'ai pas trouvé de réponses sur internet. Merci!

+0

Oui, vous devez synchroniser la boucle comme vous l'avez fait. Faire des ajouts à l'intérieur de la boucle est thread-safe mais votre liste devrait être immuable pendant la boucle –

+0

Vous pouvez également être intéressé par la lecture de [Pourquoi n'y a-t-il pas de SortedList en Java?] (Https://stackoverflow.com/questions/8725387/why -is-there-no-sortedlist-en-java). –

+1

Aussi: vous n'ajouterez jamais le premier élément à la liste avec cette logique, donc la liste restera vide pour toujours :) –

Répondre

1

Est-il vrai que pour la boucle utilise réellement l'itérateur et donc je dois envelopper avec pour synchronisé?

Votre question comporte deux parties. Tout d'abord, non, vous n'utilisez pas d'itérateur ici, c'est une base pour la boucle.

La version améliorée pour la boucle est la boucle qui utilise un itérateur:

for (T element : list) { ... } 

Vous pouvez voir in the language spec comment cela utilise le iterator - chercher où il est dit « L'amélioration de la déclaration est équivalente à une base pour déclaration du formulaire ". Deuxièmement, même si vous n'utilisez pas d'itérateur, vous avez besoin synchronized. Les deux sont orthogonaux.

Vous effectuez plusieurs opérations (size, get et add), avec des dépendances entre eux. Vous devez vous assurer qu'aucun autre thread interfère avec votre logique:

  • le get dépend du size, puisque vous ne voulez pas essayer d'obtenir un élément avec index >= size, par exemple;
  • le add dépend du get, puisque vous essayez apparemment de vous assurer que les éléments de la liste sont triés. Si un autre thread peut se faufiler et changer l'élément après vous, vous pouvez insérer le nouvel élément au mauvais endroit.

Vous évitez correctement cette interférence possible grâce à la synchronisation sur cette list, et la création du synchronizedList de telle sorte que rien d'autre que le synchronizedList peut obtenir un accès direct à la liste sous-jacente.

1

Si votre argument arg2.compareTo (arg) ne renvoie jamais 0 (zéro), vous pouvez utiliser TreeSet.Sera beaucoup plus simple:

set = Collections.synchronizedSet(new TreeSet<T>()); 

public void add(T arg) { 
    set.add(arg); 
} 

Si vous avez besoin maintenir mêmes éléments (compareTo retourne 0) puis utilisez la liste:

list = new ArrayList<T>(); 

public void add(T arg) { 
    synchronized (list) { 
     int index = Collections.binarySearch(list, arg); 
     list.add(index, arg); 
    } 
} 

première et deuxième complexité des cas seront log (N) (10 pour 1000 articles). La complexité de votre code est N (1000 pour 1000 éléments).

+1

Vous pourriez simplement utiliser 'Collections.binarySearch' pour trouver l'élément dans la liste, et alors vous n'auriez pas besoin de la restriction de' arg2.compareTo (arg)! = 0'. –

+0

Merci. Mettre à jour le deuxième cas avec binarySearch – alexey28