wake-up-neo.com

so erstellen Sie eine synchronisierte Arrayliste

ich habe synchronisierte ArrayList wie folgt erstellt

import Java.text.SimpleDateFormat;
import Java.util.*;


class HelloThread  
{

 int i=1;
 List arrayList;
  public  void go()
  {
 arrayList=Collections.synchronizedList(new ArrayList());
 Thread thread1=new Thread(new Runnable() {

  public void run() {
  while(i<=10)
  {
   arrayList.add(i);
   i++;
  }
  }
 });
 thread1.start();
 Thread thred2=new Thread(new Runnable() {
  public void run() {
     while(true)
     {
   Iterator it=arrayList.iterator();
      while(it.hasNext())
      {
       System.out.println(it.next());
      }
     }
  }
 });
 thred2.start();
  }
 }

public class test
{
  public static void main(String[] args)
  {
   HelloThread hello=new HelloThread();
   hello.go();
  }
}

aber immer Ausnahme davon

Ausnahme im Thread "Thread-1" Java.util.ConcurrentModificationException

stimmt etwas mit meinem Ansatz nicht?

12
Lalchand

Iterator von synchronizedList ist nicht synchronisiert (und kann nicht synchronisiert werden). Sie müssen die Liste während der Iteration manuell synchronisieren (siehe javadoc ):

synchronized(arrayList) {
    Iterator it=arrayList.iterator(); 
    while(it.hasNext()) { 
        System.out.println(it.next()); 
   } 
}

Ein anderer Ansatz besteht darin, eine CopyOnWriteArrayList anstelle von Collections.synchronizedList() zu verwenden. Es implementiert eine Copy-on-Write-Semantik und erfordert daher keine Synchronisation.

26
axtavt

Andere Antworten haben das Problem identifiziert:

  • Die Iteratoren für synchronisierte Sammlungen sind nicht synchronisiert. Tatsächlich handelt es sich lediglich um die Iteratoren, die von den Auflistungsobjekten in den Wrapperklassen zurückgegeben werden.

  • Viele Auflistungsklassen (einschließlich ArrayList) verwenden einen Fail-Fast-Mechanismus, um gleichzeitige Änderungen während der Iteration zu erkennen. Dieses Verhalten ist in den Javadocs für die jeweiligen Klassen eindeutig dokumentiert. Das sehen Sie.

Dies tun nicht alle Sammlungsklassen. Beispielsweise erlauben viele der Java.util.Concurrent...-Auflistungsklassen eine gleichzeitige Änderung während der Iteration, lockern jedoch die Semantik der Iterationssequenz, sodass die Ergebnisse der Änderungen kann oder kann nicht in den vom Iterator zurückgegebenen Objekten sichtbar werden.

Das Javadoc für die Collections.synchronizedList() erklärt, wie der Iterator synchronisiert wird. Grundsätzlich machst du das:

List list = Collections.synchronizedList(new ArrayList());
  ...
synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

(Abgesehen davon: Normalerweise ist es nicht sicher anzunehmen, dass so etwas funktionieren würde. Theoretisch könnte die synchronisierte Liste ein privates Sperrobjekt verwenden, und die Anweisung synchronized würde gleichzeitige Änderungen nicht sperren. Die Javadocs geben jedoch an, dass dies der Fall ist in diesem Fall zu tun ... so ist es sicher.)

Das Problem dabei ist, dass durch das Sperren der Auflistung ein potenzieller Parallelitätsengpass entsteht. Die Alternative zu ist die Verwendung einer Copy-on-Write-Datenstruktur, die intern eine Kopie der relevanten Teile der Sammlung erstellt. Dieser Ansatz bedeutet, dass ein Iterator einen Schnappschuss der Sammlung sieht. Änderungen an der Sammlung können gleichzeitig mit einer Iteration vorgenommen werden, der Iterator sieht sie jedoch nicht. Das Problem beim Kopieren beim Schreiben ist, dass Änderungen möglicherweise viel teurer sind.

Letztendlich müssen Sie die Eigenschaften und Kosten der verschiedenen Sammlungstypen für die gleichzeitige Änderung im Verhältnis zu Ihren tatsächlichen Anforderungen abwägen. Schaffst du es nicht, dass der Iterator nicht alle gleichzeitigen Änderungen sieht?

11
Stephen C

Erwägen Sie die Verwendung einer CopyOnWriteArrayList , die threadsicher ist. Jedes Mal, wenn Sie ein Element hinzufügen, wird eine neue Kopie des zugrunde liegenden Arrays erstellt. Der Iterator gibt jedoch keine Hinzufügungen zur Liste wieder, seit der Iterator erstellt wurde. Es wird jedoch garantiert, dass ConcurrentModificationException nicht ausgelöst wird.

arrayList=new CopyOnWriteArrayList();
10
dogbane

Die Java.util.ConcurrentModificationException tritt auf, wenn Sie eine Sammlung bearbeiten (hinzufügen, entfernen), während Sie dieselbe Sammlung durchlaufen.

Wahrscheinlich möchten Sie die erstellten Einträge in Ihrem zweiten Thread verwenden, nachdem sie von Ihrem ersten Thread erstellt wurden. Sie können also ArrayLists get( index ) und size() zur Steuerung verwenden

3
stacker

Wie Spike sagte, können Sie eine Sammlung nicht ändern, während Sie sie iterieren. Ich denke jedoch, dass die Lösung darin besteht, die Liste während des Iterierens zu sperren.

class HelloThread  
{

 int i=1;
 List arrayList;
  public  void go()
  {
 arrayList=Collections.synchronizedList(new ArrayList());
 Thread thread1=new Thread(new Runnable() {

  public void run() {
  while(i<=10)
  {
synchronized(someLock) {
   arrayList.add(i);
}
   i++;
  }
  }
 });
 thread1.start();
 Thread thred2=new Thread(new Runnable() {
  public void run() {
     while(true)
     {
synchronized(someLock) {
   Iterator it=arrayList.iterator();
      while(it.hasNext())
      {
       System.out.println(it.next());
      }
}
     }
  }
 });
 thred2.start();
  }
 }

public class test
{
  public static void main(String[] args)
  {
   HelloThread hello=new HelloThread();
   hello.go();
  }
}

Ich bin nicht sicher, was Sie versuchen, also hoffe ich, dass dies die Funktionalität Ihres Codes nicht beeinträchtigt.

2

Nehmen wir eine normale Liste (von der ArrayList-Klasse implementiert) und synchronisieren sie. Dies wird in der SynchronizedArrayList-Klasse angezeigt. Wir übergeben der Collections.synchronizedList-Methode eine neue ArrayList of Strings. Die Methode gibt eine synchronisierte Liste von Zeichenfolgen zurück. // Hier ist das SynchronizedArrayList-Klassenpaket com.mnas.technology.automation.utility; import Java.util.ArrayList; Java.util.Collections importieren; 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());
}
}

}
}

Notice that when iterating over the list, this access is still done using a synchronized block that locks on the synchronizedList object. 
In general, iterating over a synchronized collection should be done in a synchronized block
0
user4423251

Sie dürfen eine Sammlung, die Sie iterieren, nicht ändern. Sie können dies umgehen, indem Sie nicht über einen Iterator, sondern über den Index auf die Arrayeinträge zugreifen. Ich kann Ihnen weitere Ratschläge geben, wenn Sie mir das Problem mitteilen, das Sie mit diesem Code lösen möchten.

0
Spike Gronim