English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
L'implémentation de la taille variable de l'array pour l'interface List. Elle réalise toutes les opérations optionnelles de la liste et permet tous les éléments, y compris null. En plus de réaliser l'interface List, cette classe fournit également des méthodes pour manipuler la taille du tableau utilisé pour stocker la liste. (Cette classe est globalement équivalente à la classe Vector, sauf qu'elle n'est pas synchronisée.) Les opérations size, isEmpty, get, set, iterator et listIterator s'exécutent en temps constant. L'opération add s'exécute en temps amorti constant, ce qui signifie que l'ajout de n éléments nécessite un temps de complexité O(n). Toutes les autres opérations s'exécutent en temps linéaire (en gros). Par rapport aux facteurs constants utilisés pour l'implémentation LinkedList, cette implémentation a des facteurs constants plus bas. Chaque instance d'ArrayList a une capacité. La capacité est la taille du tableau utilisé pour stocker les éléments de la liste. Elle est toujours au moins égale à la taille de la liste. Avec l'ajout continu d'éléments à l'ArrayList, la capacité augmente automatiquement. Les détails de la stratégie de croissance ne sont pas spécifiés, car ce n'est pas aussi simple que l'ajout d'éléments qui entraîne des coûts de temps amortis fixes. Avant d'ajouter un grand nombre d'éléments, l'application peut utiliser l'opération ensureCapacity pour augmenter la capacité de l'instance d'ArrayList. Cela peut réduire le nombre de réallocations successives.
Attention, cette implémentation n'est pas synchronisée.
Si plusieurs threads accèdent simultanément à une instance d'ArrayList et qu'au moins un d'entre eux modifie la liste structuralement, celle-ci doit être synchronisée externement. (Une modification structuralement signifie toute opération d'ajout ou de suppression d'un ou plusieurs éléments, ou un ajustement explicite de la taille du tableau sous-jacent ; ne pas modifier simplement la valeur d'un élément n'est pas une modification structuralement.) Cela est généralement réalisé par des opérations de synchronisation sur l'objet qui encapsule naturellement la liste. Si tel objet n'existe pas, il convient d'utiliser la méthode Collections.synchronizedList pour envelopper cette liste. Il est préférable de le faire lors de la création pour éviter tout accès non synchronisé accidentel à la liste :
Listlist=Collections.synchronizedList(newArrayList(...));
此类的iterator和listIterator方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的remove或add方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测bug。
如上所示,现在建立一个list集合,一个线程对集合进行写入操作,一个线程进行删除操作
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Random; public class MyArrayList { /** * Créer une liste, un thread pour écrire, un thread pour lire les itérateurs iterator et listIterator retournés sont rapidement en faillite */ public void readWrite() { List<Integer> nums = new ArrayList<Integer>(); List<Integer> synNums = Collections.synchronizedList(nums); //Démarrer le thread d'écriture new WriteListThread(synNums).start(); //Démarrer le thread de suppression new DeleteListThread(synNums).start(); } public static void main(String[] args) { new MyArrayList().readWrite(); } } class WriteListThread extends Thread { private List<Integer> nums; public WriteListThread(List<Integer> nums) { super(“WriteListThread”); this.nums = nums; } // Écrire des éléments en continu1 public void run() { while (true) { nums.add(new Random().nextint(1000)); System.out.println(Thread.currentThread().getName()); } } } class DeleteListThread extends Thread { private List<Integer> nums; public DeleteListThread(List<Integer> nums) { super(“DeleteListThread”); this.nums = nums; } // Supprimer l'élément premier public void run() { while (true) { try{ System.out.println(Thread.currentThread().getName()+:+nums.remove(0)); } catch(Exception e){ continue ; } } } }
通过List<Integer>synNums=Collections.synchronizedList(nums);就能对原子操作进行同步了,但是官方api示例为什么要自己手动添加同步呢?
List list = Collections.synchronizedList(new ArrayList()); synchronized(list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }
查看Collections.synchronizedList的源代码
SynchronizedCollection(Collection<E> c) { if (c==null) throw new NullPointerException(); this.c = c; mutex = this; }
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Random; public class MyArrayList { /** * Créer une liste, un thread pour écrire, un thread pour lire les itérateurs iterator et listIterator retournés sont rapidement en faillite */ public void readWrite() { List<Integer> nums = new ArrayList<Integer>(); List<Integer> synNums = Collections.synchronizedList(nums); //Démarrer le thread d'écriture new WriteListThread(synNums).start(); //Démarrer le thread de suppression new DeleteListThread(synNums).start(); } public static void main(String[] args) { new MyArrayList().readWrite(); } } class WriteListThread extends Thread { private List<Integer> nums; public WriteListThread(List<Integer> nums) { super("WriteListThread"); this.nums = nums; } // Écrire des éléments en continu1 public void run() { while (true) { nums.add(new Random().nextint(1000)); System.out.println(Thread.currentThread().getName()); } } } class DeleteListThread extends Thread { private List<Integer> nums; public DeleteListThread(List<Integer> nums) { super("DeleteListThread"); this.nums = nums; } // Supprimer l'élément premier public void run() { while (true) { try{ System.out.println(Thread.currentThread().getName()+:"+nums.remove(0)); } catch(Exception e){ continue ; } } } }
Il est可见 pour les opérations synchronisées sur la collection, en utilisant les outils de包装 de Collections synchronisée, mais encore plus pour les opérations non atomiques, les utilisateurs doivent manuellement procéder à la synchronisation
Comme indiqué ci-dessous, ajouter un thread pour lire la collection
class ReadListThread extends Thread { private List<Integer> nums; public ReadListThread(List<Integer> nums) {}} super(“ReadListThread”); this.nums = nums; } // Lecture continue des éléments, opération non atomique, nécessitant manuellement l'ajout de verrous public void run() { while (true) { //Sommeil, transférer le verrou à d'autres threads try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } synchronized (nums) { if (nums.size() > 100) { Iterator<Integer> iter = nums.iterator(); while (iter.hasNext()) { System.out.println(Thread.currentThread().getName() + : + iter.next()); ; } } else{ try { nums.wait(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
Résumé
Voici tous les détails de la synchronisation des threads du cadre de collection Java, j'espère qu'ils vous seront utiles. Les amis intéressés peuvent continuer à consulter d'autres sujets pertinents sur ce site. Si il y a des insuffisances, n'hésitez pas à laisser un message. Merci de votre soutien à ce site !
Déclaration : le contenu de cet article est issu du réseau, et appartient au propriétaire original. Le contenu est contribué et téléversé par les utilisateurs d'Internet de manière spontanée. Ce site ne possède pas de propriété, n'a pas été édité par l'homme, et n'assume aucune responsabilité juridique. Si vous trouvez du contenu présumé violer les droits d'auteur, n'hésitez pas à envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation, et fournir des preuves pertinentes. Une fois vérifié, ce site supprimera immédiatement le contenu présumé enfreindre les droits d'auteur.