Synchronized - auf welchem Objekt

redbomber

Bekanntes Mitglied
Hi zusammen,

ich habe eine Frage:
Ich besitze eine statische Klasse die ein Array von DateFormat Objekten anbietet. Dieser Klasse kann ein String übergeben werden, welcher in ein Date formatiert wird.
Da DateFormat nicht threadSafe ist, habe ich den Block wo der String geparsed wird synchronisiert.

An dem folgendem Code könnt ihr sehen wie ich synchronisiere. Könnt ihr mir erklären warum Variante 1 nicht funktioniert. Variante 2 sollte funktionieren, aber nich nicht ausreichend getestet.

Java:
class MyClass{
	static DateFormat[] formats[]={...}
	
	//variante 1 
	static Date parse(String aDate){
		Date date;
		for(int i=0; i< formats.length; i++){
			synchronized(MyClass.class){
				date = formats[i].parse(aDate);
			}
			
			if(date!=null){
				return date;
			}
		}
		return date;
	}
	
	//variante 2 
	static Date parse(String aDate){
		Date date;
		for(int i=0; i< formats.length; i++){
			synchronized(formats[i]){
				date = formats[i].parse(aDate);
			}
			
			if(date!=null){
				return date;
			}
		}
		return date;
	}
}
 
Zuletzt bearbeitet:
was gibt es da zu erklären, das hat nichts mit Synchronisierung oder DateFormat zu tun,
in einer statischen Methode gibt es kein this, fertig?

oder erhälst du nicht bereits einen Compilerfehler? sondern stattdessen was anderes, läuft das Programm, funktioniert nur der gegenseitige Ausschluss nicht?
ausführliche Informationen, die Welt wäre so dankbar..
 
Zuletzt bearbeitet von einem Moderator:
aber auch wenn die klasse nicht-statisch wäre, könne man über this nicht syncen. this bezieht sieht auf das aktuelle objekt und ist in jeder instanz logischerweiße unterschiedlich.
 
Mal abgesehen davon, dass ich den Sinn hinter der Synchronisation nicht verstehe, gibt es im statischen Kontext kein this, daher lässt sich Variante 1 nicht kompilieren.

Wozu das synchronized?
 
sorry leute.
Erst einmal hatte ich den code falsch geposted. habe ich eben aktualisiert.
Ich synchronisiere auf
Java:
synchronized(MyClass.class)

Ok, bei diesem Code wäre ich davon ausgegangen dass auf der einigsten Instanz von "MyClass" synchronisiert wird.

Wenn ich diese Methode jedoch anwende, dann erhalte ich unvorhersehbare Antworten aus der Methode DateFormat.parse().
Im grunde genau alle Antowrten die in diesem Post gefunden hatte:

fahd.blog: DateFormat with Multiple Threads

In diesem Post werden mehrere Möglichkeiten angeboten wie ich das problem behebe. Ich hab mich für den synchronized block entschieden.

In meinem Fall wird auf ein DateFormat in dem Array meiner Klasse MyClass immer nur von einem Thread aus zugegriffen.
Genau das was ich möchte.

Nun verstehe ich aber nicht warum meine erste Variante nicht auch funktioniert?
 
Zuletzt bearbeitet:
ich glaube der fehler liegt hier eher bei dir selbst da du dieses NOT THREADSAFE total falsch verstehst ...
NOT THREADSAFE bedeutet nich das man syncen muss ... sondern das es zu einem unerwartetem ereignis innerhalb des aufrufenden threads führen kann ...

also befasse dich bitte erstmal mit dem statement NOT THREADSAFE ... und dann kannst du noch mal selbst überlegen was für einen fehler du begangen hast

tipp : synchronized bedeutet nur das auf eine methode nur eine instanz gleichzeitig zugreifen kann und steht gewöhnlich als modfier in der methoden-signatur
 
@despikyxd
nanu, dann verstehe ich NOT THREADSAFE aber auch falsch..

bei google eingetippt wird man etwa zu
Thread safety - Wikipedia, the free encyclopedia
geleitet, was dort alles steht kann man im Detail lesen und auf verschiedenste Weisen interpretieren, ich zitiere aber zumindest
Mutual exclusion or Process synchronization

Access to shared data is serialized using mechanisms that ensure only one thread reads or writes the shared data at any time.

synchronized-Blöcke statt ganze Methoden sind meiner Ansicht nach auch ok,

könntest du deine Gedanken weiter ausführen?

------

@redbomber
wieso Synchronisierung über die Klasse nicht funktioniert kann ich derzeit nicht sagen,
funktioniert denn das andere? wenn auch nicht, dann muss es generell einen anderen Grund geben
 
Zuletzt bearbeitet von einem Moderator:
Hmm, also ich habe mir eine Test-Klasse geschrieben, die eben genau das testen soll.
Hier lasse ich mehrere Threads parallel laufen, die auf EINEM DateFormat einen String in eine Date parsen.

1.
Ohne jegliches Synchronized kommt es zu vielen unvorhersagbaren Ergebnissen und Exceptions.
Was auch zu erwarten war.

2.
Synchronisiere ich auf:
Java:
synchonized(MyClass.class){
...
}
Dann klappt der Test leider auch, was nicht zu erwarten war.
Zumindest hatte ich diese Implementierung bisher so und es gab immer wieder Exceptions.

3.
Synchronisiere auf auf das Objekt vom DateFormat
Java:
synchonized(formats[i]){
...
}
Hier klappt der Test.


Da Test 2 auch funktioniert kann ich also nicht mit Sicherheit sagen ob der Fehler nun behoben ist.
 
Dann klappt der Test leider auch, was nicht zu erwarten war.
Warum war das nicht zu erwarten? MyClass.class ist ein globales Objekt, das kann man zum Synchronisieren benutzen.
Ich würde hier gar nicht mit synchronized arbeiten, sondern die Formate einfach lokal erzeugen (wie viele sind das denn? 500?)
 
Warum war das nicht zu erwarten? MyClass.class ist ein globales Objekt, das kann man zum Synchronisieren benutzen.
Ja ist richtig, ich hatte nur auf MyClass.class synchronisiert und es gab immer wieder unvorhersagbare Ergebnisse.
Wär mein Test hier auch fehlgeschlagen, dann könnte ich zumindest sagen dass es jetzt sicher funktioniert wenn ich auf das passende DateFormat synchronisiere...
Jetzt weiss ich nicht ob meine neue Lösung das Problem wirklich behebt.

also in
Java:
static DateFormat[] formats[]={...}
hab ich mehrere DateFormat Objekte, vielleicht 10.

Die Formate lokal erzeugen ist zu aufwendig, da MyClass.format() an sehr vielen Stellen im Code aufgerufen wird.
In einer Schleife wird dann durch alle Formatter gelaufen, bis ein passendes Ergebnis erzeugt wurde.

Die Synchronisation erscheint mir die einzigste Möglichkeit die ich habe um die unvorhersagbaren Ergebnisse zu vermeiden.
 
Zuletzt bearbeitet:
Also, wo anfangen? Code, der unvorhersagbare Termine ausgibt - sehr gut^^

2. ThreadLocals
Another approach is to use a ThreadLocal variable to hold the DateFormat object, which means that each thread will have its own copy and doesn't need to wait for other threads to release it. This is generally more efficient

Glaube ich nicht so richtig dran, das es effizienter ist, bei vielen Threads viele Instanzen von DateFormat zu erzeugen.

Über die Instanzen der einzelnen DateFormat zu synchronisieren ist der richtige Weg, allerdings kostete es Zeit, den Block zu betreten und wahrscheinlich ist es effizienter, die ganze Schleife innerhalb des sync-Blocks zu schreiben. Teste das mal, also die Synchronisation auf der Variable des Arrays. So gesehen, wären sogar Änderungen der Array-Elem möglich.
 
ich glaube der fehler liegt hier eher bei dir selbst da du dieses NOT THREADSAFE total falsch verstehst ...
NOT THREADSAFE bedeutet nich das man syncen muss ... sondern das es zu einem unerwartetem ereignis innerhalb des aufrufenden threads führen kann ...

also befasse dich bitte erstmal mit dem statement NOT THREADSAFE ... und dann kannst du noch mal selbst überlegen was für einen fehler du begangen hast
Entweder erzählst du hier eine Menge Käse, oder du hast dich nur etwas ungünstig ausgedrückt (wovon ich ausgehe). Natürlich muss man eine Stelle, die nicht threadsafe ist nicht synchronisieren. Aber nur wenn es eine single-threaded Anwendung ist. Sonst muss man sie synchronisieren, weil eben wie du schon sagtest sonst unvorhersehbare Ergebnisse (oder Exceptions) auftreten können.

tipp : synchronized bedeutet nur das auf eine methode nur eine instanz gleichzeitig zugreifen kann und steht gewöhnlich als modfier in der methoden-signatur
Von gewöhnlich kann man nicht wirklich sprechen. Kritische Sektionen sollten so klein wie möglich sein, somit ist ein synchronisierter Block u.U. sinnvoll, wenn man nicht die gesamte Methode synchronisieren möchte.
 
Also erst einmal euch allen vielen vielen Dank!

Über die Instanzen der einzelnen DateFormat zu synchronisieren ist der richtige Weg, allerdings kostete es Zeit, den Block zu betreten und wahrscheinlich ist es effizienter, die ganze Schleife innerhalb des sync-Blocks zu schreiben. Teste das mal, also die Synchronisation auf der Variable des Arrays. So gesehen, wären sogar Änderungen der Array-Elem möglich.
Habe ich ich nicht getestet, werde ich aber prüfen. Versuche auch mal zu messen obs da zeit-unterschiede gibt.

Ich habe jetzt viele Stunden mein Programm laufen lassen und bisher gibt es nur die erwünschten Ergebnisse.
Zuvor kam es bei einer deutlich kürzeren Laufzeit, als ich noch auf MyClass.class synchronisiert hatte, mehrmals zu unvorhersagbaren Ergebnissen.

Meine Test-Klasse funktioniert "leider" bei beiden Varianten. Aber ich denke den Fall, der während des Programm-Ablaufs auftritt ist zu zufällig. Den kann ich in meinem Test nicht wirklich simulieren.
Da das Programm jetzt aber durchgelaufen ist, bin ich zufrieden.
Ich denke ich habs nun mit eurer Hilfe gelöst!
 
Von gewöhnlich kann man nicht wirklich sprechen. Kritische Sektionen sollten so klein wie möglich sein, somit ist ein synchronisierter Block u.U. sinnvoll

Diese Faustregel gilt immer? Auch für sync-Blöcke mit sehr kurzen Schleifen, die höchstwahrscheinlich sequentiell durchlaufen werden? da lass ich mich auf wette ein.

schlimmstenfalls würde man n*m oft warten müssen, wenn n anzahl der konkurrierenden threads, m anzahl der Formats; bestenfalls 0-mal und bei synchronisation nur einen Formats mindestens n-mal 😉
 
Diese Faustregel gilt immer? Auch für sync-Blöcke mit sehr kurzen Schleifen, die höchstwahrscheinlich sequentiell durchlaufen werden? da lass ich mich auf wette ein.

schlimmstenfalls würde man n*m oft warten müssen, wenn n anzahl der konkurrierenden threads, m anzahl der Formats; bestenfalls 0-mal und bei synchronisation nur einen Formats mindestens n-mal 😉

Das macht doch so in der Regel keinen Sinn... es geht um kleinere Synchronisationsblöcke als die ganze Methode... und so klein wie möglich aber so groß wie nötig. Wenn es keinen Sinn macht, ist es nicht möglich.
 
ich bezweifle, dass du weißt, was ich meine. es geht darum, ob

Java:
public static String met() {
    String result = "";
    for (int i = 0; i < 5; i++) {
        synchronized(array[i]) {
        result = array[i].metOther();
        }
    }
    return result;
}

oder

Java:
public static String met() {
    String result = "";
    synchronized(array) {
    for (int i = 0; i < 5; i++) {
        result = array[i].metOther();
    }
    }
    return result;
}

für wieviele threads schneller wäre oder nicht...

unabhängig davon, wie viel sinn das macht, ist
- die schleife relativ kurz,
- kostet der eintritt in den sync-block zeit,
- kann es sein, dass oft die schleife ganz durchlaufen wird, auch bei mehrern gleichzeitig laufenden threads

schwer zu sagen, was schenller wäre. unabhängig (auch) davon sind einige neuere schnellere methoden zur synchronisierung noch gar nicht genannt worden und werden auch nicht in dem blog-beitrag erwähnt - aber darum ging es ja auch eigentlich nicht.
 

Neue Themen


Zurück
Oben