Synchronisation

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo

in Punkte Synchronisation hab ich bis Dato keine Erfahrung. Ich stehe vor folgendem Problem:

Ich habe in einer Klasse ein Map

Code:
private Map<String,Client> con;

Jetzt gibt es einen Thread der in die Map einträge einfügt und einen weiteren der per Iteration durch die Map läuft und einträge ausließt. Theoretisch kann es passieren das beide das gleichzeitig versuchen. Wie kann ich die Map denn nun Synchronisieren so das, wenn ich gerade schreibe der LeseThread wartet bzw. wenn ich gerade lese der SchreibThread wartet.

Wäre klasse wenn jemand ein Beispiel für mich hat.

Danke
 

Tobias

Top Contributor
Für dieses spezielle Problem gint es
Code:
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
in der Klasse Collections. Oben die unsynchronisierte Map rein, unten die synchronisierte Map rausnehmen. Kurz abkühlen lassen, fertig.

mpG
Tobias
 
G

Gast

Gast
Verstehe ich das richtig, ich packe in eine Map eine Synchronized Map? Wie durchlauf ich diese denn dann per Iteration?
 

Tobias

Top Contributor
Deine Map heißt con. Deine Map ist (wenn es nicht gerade eine Hashtable ist) unsynchronisiert und damit bei dem, was du vorhast, gefährdet. Mit

Code:
Map<String, Client> syncCon = Collections.<String, Client>synchronizedMap(con);

bekommst du eine synchronisierte "View" auf deine unsynchronisierte Map con. Mit syncCon kannst du jetzt in mehreren Threads arbeiten. Das Problem der failfast-Iteratoren wird aber bestehen bleiben, so dass diese Maßnahme nicht ausreichend sein wird ...

mpG
Tobias
 

Marco13

Top Contributor
Ja, synchronisation muss sein, wie Tobias beschrieben hat. Die Sache mit den ConcurrentModifications könnte man so in den Griff kriegen

Vorher
Code:
// Thread 1:
for (Object a : map.values()) { .... }

// Thread 2:
for (int i=0; i<3; i++)
{
    map.put(i, new Object());
}


Nachher:
Code:
// Thread 1:
synchronized (map)
{
    for (Object a : map.values()) { .... }
}

// Thread 2:
Map toAdd = new HashMap();
for (int i=0; i<3; i++)
{
    toAdd.put(i, new Object());
}
map.addAll(toAdd);

*kurzüberleg* ... ja, müßte passen.
 
G

Guest

Gast
Hallo Tobias, Hallo Marco,

danke für die Tips aber so ganz klar ist mir das noch nicht.

Ich habe eine Klasse die für die Verwaltung der Map zuständig ist. Diese sieht derzeit so aus:

Code:
public class IfImpl implements IfInterface {

   private Map<String,Client> con;

   public IfImpl(){
      con = Collections.synchronizedMap(new HashMap<String,Client>());
   }


   public addClient(String id, Client cl){
     con.add(id,cl);
   }

   public runClient(){
     Iterator it = con.keySet().iterator();
     while (it.hasNext()){
       Client cl = (Client)con.get((String)it.next());
       cl.run();
     }
   }
}

Daneben gibt es zwei Threads die die Funktionen runClient bzw. addClient aufrufen und das ggf. gleichzeitig.

Wenn ich Marko jetzt richtig verstehe muss ich die Funktion runClient lediglich synchronized machen? Etwa so:

Code:
public class IfImpl implements IfInterface {

   private Map<String,Client> con;

   public IfImpl(){
      con = Collections.synchronizedMap(new HashMap<String,Client>());
   }


   public addClient(String id, Client cl){
     con.add(id,cl);
   }

   public synchronized runClient(){
     Iterator it = con.keySet().iterator();
     while (it.hasNext()){
       Client cl = (Client)con.get((String)it.next());
       cl.run();
     }
   }
}

Die Angaben von Marko in //Thread 2 kann ich übersrpingen? da ich in der Funktion addClient() sowieso lediglich einen Client einfüge.

Verstehe ich das richtig?

Danke für eure Hilfe
 

Marco13

Top Contributor
Hmnee, addClient müßte dann auch synchronized sein. Allerdings bräuchte man dann glaubich nichmal mehr eine synchronizedMap, weil ja ALLE Zugriffe auf die Map schon durch IfImpl synchronisiert werden.
 
G

Gast

Gast
Mhm ein Buch mit sieben Siegeln ;-)

Aber die beiden Threads könnten doch theoretisch gleichzeitig addClient und runClient aufrufen. Ich verstehe nicht woher das Programm weiß das wenn addClient aufgerufen wird ein runClient nicht aufgerufen werden darf bzw. warten muss bis runClient fertig ist und umgekehrt?
 

Marco13

Top Contributor
Wenn man das "synchronized" vor eine Methode schreibt, wird auf das jeweilige Objekt synchronisiert. Sowas
Code:
public synchronized void foo() 
{ 
    doit();
}
ist also ganz grob gleichbedeutend mit
Code:
public void foo() 
{ 
    synchronized (this)
    {
        doit();
    }
}

D.h. wenn deine beiden Methoden synchronized sind, ist sichergestellt, dass immer nur ein Thread eine von beiden ausführt. Jeder andere Thread, der die gleiche Methode (oder eine andere synchronized-Methode) ausführen will, muss warten.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben