# Mehrere Threads greifen auf eine Klasse zu



## The_S (28. Mrz 2006)

Hi!

Ich habe eine Klasse (nennen wir sie mal "Speicher") in welcher mehrere Objekte einer anderen Klasse mitsamt id in einer HashMap gespeichert und auch wieder rausgelöscht werden. Die Daten müssen nicht in der Reihenfolge gelöscht werden, wie sie gespeichert wurden. D. h. ich hab meinetwegen die ids

1
2
3
4
5
6
7

vergeben und lösche dann einige (1, 3, 6) raus, dass dann die ids

2
4
5
7

bestehen bleiben. Jetzt kommt wieder eine Klasse hinzu, mein Programm überprüft welche kleinstmögliche id (damit ich wenigstens ein wenig Ordnung hab  ) nicht vergeben ist, stellt fest dass es sich um die 1 handelt und speichert die Klasse mitsamt id in der Hashmap. Folglich sind dann das

1
2
4
5
7

die Vergebenen IDs. Soweit kein Problem. Nur greifen u.U. mehrere Threads auf das selbe Objekt der Klasse Speicher zu und wollen Daten hinzufügen =>  1. Thread schaut nach, sieht dass die 3 frei ist, aber bevor er die 3 zuweisen kann, schaut der 2. Thread auch nach welche id frei ist und stellt natürlich auch die 3 fest. Das hat dann freilich zur Folge, dass das 1. Objekt in der Hashmap mit dem 2. gleich wieder überschrieben wird => nicht gut ...

Da ich damit noch überhaupt keine Erfahrung gemacht habe, hätte ich da mal zwei Fragen:

1. Läuft das wirklich so ab, wie ich mir das Denke oder mache ich mir ganz umsonst Gedanken?
2. Falls ja, wie kann ich das Problem umgehen?

Danke für die Antworten!


----------



## norman (28. Mrz 2006)

sollte es nicht schon ausreichen, die methode(n), in der du nach einem freinen platz suchst und die klasse in die tabelle einträgst, als *synchronized* zu deklarieren?
oder denk ich da nicht genügend um die ecke ???:L


----------



## The_S (28. Mrz 2006)

norman hat gesagt.:
			
		

> sollte es nicht schon ausreichen, die methode(n), in der du nach einem freinen platz suchst und die klasse in die tabelle einträgst, als *synchronized* zu deklarieren?
> oder denk ich da nicht genügend um die ecke ???:L



kA, hab wie gesagt noch nichts damit gemacht. Deswegen frag ich ja


----------



## norman (28. Mrz 2006)

wenn schon ein thread nach freien plätzen suchst, bevor ein anderer den gefunden freien wieder besetzt hat, sollte synchronized abhilfe schaffen. dann kann thread2 erst loslegen, wenn thread1 mit der synchronized methode fertig ist. 
evtl ist es dann geschickter, die sucheFreienPlatz() und schreibDichDaRein() und keine ahnung was methoden aus einer weiteren aufzurufen, die dann eben synchronized als attribut hat.


----------



## bygones (28. Mrz 2006)

wirst wohl nicht rumkommen dich in Concurrent Programming einzulesen.

Für den Anfang sollte die bekannten Java Online Bücher Infos über Threads / synchronized usw. reichen


----------



## The_S (28. Mrz 2006)

deathbyaclown hat gesagt.:
			
		

> wirst wohl nicht rumkommen dich in Concurrent Programming einzulesen.
> 
> Für den Anfang sollte die bekannten Java Online Bücher Infos über Threads / synchronized usw. reichen



Also reicht ein simples "synchronized" nicht aus!?


----------



## byte (28. Mrz 2006)

Es gibt zu dem Thema halt zig Algorithmen oder Konzepte (Transaktionen, Semaphoren, ...). Aber ich denke mal, in Deinen Fällen müsste es ausreichend sein, wenn Du den Zugriff auf Deine Datenstruktur synchronisierst. Die meisten Konzepte gehen eher in Richtung verteilter Anwendungen.


----------



## The_S (28. Mrz 2006)

ok, danke für eure Antworten. Setze das jetzt erstmal synchronized und werde mich nebenbei dennoch mal in die Thematik einlesen.


----------



## Leroy42 (28. Mrz 2006)

Es wird mit synchronized funktionieren. Du mußt hier allerdings sorgfältig vorgehen.



			
				norman hat gesagt.:
			
		

> wenn schon ein thread nach freien plätzen suchst, bevor ein anderer den gefunden freien wieder besetzt hat, sollte synchronized abhilfe schaffen. dann kann thread2 erst loslegen, wenn thread1 mit der synchronized methode fertig ist.
> evtl ist es dann geschickter, die sucheFreienPlatz() und schreibDichDaRein() und keine ahnung was methoden aus einer weiteren aufzurufen, die dann eben synchronized als attribut hat.


Diese Beschreibung könnte mißverstanden werden. Wichtig und unverzichtbar ist,
daß es keine *zwei unabhängige* Methoden _sucheFreienPlatz() und schreibDichDaRein()_. Beides muß
in _einem Aufwisch_ entweder in einer Methode oder in einem synchronized-Block, der beide
Methoden hintereinander aufruft, erledigt werden.

Edit: P.S. an Hobbit:
Wo hast du eigentlich dieses tolle _Merkel-im-Blutrausch_-Foto her (  )
Gibts da ne Quelle? Mich interessiert vor allem, von welchem Originalwort die Silben
"töten" herkommen.


----------



## The_S (28. Mrz 2006)

Nur zum Verständnis, was ist jetzt richtig?


```
public synchronized void suchFreienPlatz() {
...
}

public synchronized void schreibDichDaRein() {
    ...
    suchFreienPlatz()
    ...
}
```

oder


```
public synchronized void suchFreienPlatz() {
...
}

public void schreibDichDaRein() {
    ...
    suchFreienPlatz()
    ...
}
```

oder


```
public void suchFreienPlatz() {
...
}

public synchronized void schreibDichDaRein() {
    ...
    suchFreienPlatz()
    ...
}
```

oder


```
public synchronized void blup() {
    schreibDichDaRein()
}

public void suchFreienPlatz() {
...
}

public void schreibDichDaRein() {
    ...
    suchFreienPlatz()
    ...
}
```

oder doch was ganz anderes? Ihr verwirrt mich nämlich gerade ein wenig ... :bahnhof:  :autsch:  ???:L

[edit] Das Hängt bei uns an der Bürotür  :lol: , kA wer das da hingehängt hat, muss gewesen sein, als ich Berufsschule oder Urlaub hatte. Hab dann einfach mal bei Google Bildersuche nach "Merkel töten" gesucht und *schwupps* schon wars da


----------



## Leroy42 (28. Mrz 2006)

Leider keins deiner Varianten   

Variante 1 (Vorzuziehen)

```
public synchronized void suchFreienPlatzUNDSchreibDichDaRein() {
}
```
Variante  (nicht empfehlenswert)

```
public int suchFreienPlatz() {
}
public void schreibDichDaRein(int pos ) {
}
public void irgendwoGanzAnders() {
    ...
    synchronized([i]deineVariable[/i]) {
        int pos = sucheFreienPlatz();
        trödelEinBischenHerum();
        schreibDichDaRein(pos);
    }
    ...

}
```

Zwei synchronized Methoden bringen nichts, da nach Abarbeitung der suchen-Methode
der Block verlassen wird und bevor dann schließlich eine Eintragung erfolgt, es passieren
kann, daß die suchen-Methode erneut aufgerufen wird.

Aus demselben Grund ist auch die Variante 2 *nur dann* sicher, wenn die beiden
Methoden *nur* hintereinander innerhalb *eines* synchronized-Blocks aufgerufen werden.


----------



## The_S (28. Mrz 2006)

Leroy42 hat gesagt.:
			
		

> Variante 1 (Vorzuziehen)
> 
> ```
> public synchronized void suchFreienPlatzUNDSchreibDichDaRein() {
> ...



Ist das dann nicht äquivalent zu meiner Methode


```
public void suchFreienPlatz() { 
... 
} 

public synchronized void schreibDichDaRein() { 
    ... 
    suchFreienPlatz() 
    ... 
}
```


----------



## Leroy42 (28. Mrz 2006)

Da hast du Recht!

Einzige Ausnahme ist, daß sucheFreienPlatz noch von woanders aufgerufen werden könnte.
Wenn du allerdings keine andere Methode hast, die etwas einträgt, wird deine Version
aber auch funktionieren.


----------



## The_S (28. Mrz 2006)

nein, hab keine andere Methode die darauf zugreift. Hatte ich das doch richtig verstanden, schock mich net immer so . Hab scho angefangen an meinem Verstand zu zweifeln ...


----------



## tini (28. Mrz 2006)

wenn niemand anderes drauf zugreift, kannste die Methode suchFreienPlatz() aber auch private machen, oder?


----------



## The_S (28. Mrz 2006)

tini hat gesagt.:
			
		

> wenn niemand anderes drauf zugreift, kannste die Methode suchFreienPlatz() aber auch private machen, oder?



ist sie auch, nur net beim schnell hingewurstelten Beispielcode


----------



## tini (28. Mrz 2006)

ahso, kann ich ja nich wissen (glaskugel und so ...).  :wink:


----------



## The_S (28. Mrz 2006)

tini hat gesagt.:
			
		

> ahso, kann ich ja nich wissen (glaskugel und so ...).  :wink:



WIE??? Keine Hellseher Klasse???  :shock: 

 :lol:


----------



## flanker (28. Mrz 2006)

ich würde es so machen:


```
public synchronized void changePool(MyObject obj, boolean delete) {
  if (delete) {
    delete(obj);
    return;
  }
  obj.setId(getNewId());
  insert(obj);
}

private int getId() {
  //Darf ausser [i]changePool[/i] niemand verwenden!
}

private void insert(MyObject obj) {
  //Darf ausser [i]changePool[/i] niemand verwenden!
}

private void delete(MyObject obj) {
  //Darf ausser [i]changePool[/i] niemand verwenden!
}
```


----------



## The_S (28. Mrz 2006)

Meinste jetzt von der Verwendung von synchronized her (hab ich auch so), oder vom Aufbau der Methoden?


----------



## flanker (28. Mrz 2006)

eigentlich beides, denn wärend du id suchst und einfügst darf Pool niht verändert werden, beim löschen genauso, wärend gelöscht wird, darf nicht mal id abgefragt werden, oder?


----------



## The_S (28. Mrz 2006)

flanker hat gesagt.:
			
		

> eigentlich beides, denn wärend du id suchst und einfügst darf Pool niht verändert werden



ja, sonst wird ein Datensatz womöglich überschrieben



			
				flanker hat gesagt.:
			
		

> beim löschen genauso, wärend gelöscht wird, darf nicht mal id abgefragt werden, oder?



nö, das ist wurst.


----------

