2013-08-19 10 views
8

In JSON-Java-Bibliothek (org.json.JSONArray) Ich habe diesen Code-Schnipsel mit einem synchronized Block um ein Verfahren lokalen Variable gefundenNotwendigkeit der Synchronisation auf lokalem Variable

public String toString(int indentFactor) throws JSONException { 
    StringWriter sw = new StringWriter(); 
    synchronized (sw.getBuffer()) { 
     return this.write(sw, indentFactor, 0).toString(); 
    } 
} 

ich die Notwendigkeit nicht für die Synchronisation verstehen hier, wie die StringWriter ist nur lokal für die angegebene Methode (und warum die Synchronisation auf dem Puffer ist). Ist die Synchronisation hier wirklich notwendig und wenn, warum?

+8

Es ist nicht notwendig. Mit dem Standardkonstruktor ist der Puffer ein neu instanziiertes Objekt. 'buf = new StringBuffer();' im Konstruktor. –

+8

Beachten Sie, dass der Autor der org.json-Bibliothek ein JavaScript-Programmierer und kein Java-Programmierer ist. Diese Tatsache wird im gesamten Code demonstriert. Für ernsthafte JSON-Verarbeitung sollten Sie die Google-Gson-Bibliothek verwenden. –

Antwort

7

Dies kann eine Performance-Optimierung sein. Im Orakel jvm ist das Wiedererlangen eines bereits gehaltenen Schlosses sehr schnell. Vermutlich führt der Anruf write zahlreiche Aufrufe in den StringBuffer. Durch das Sperren vor dem Aufruf von write wird die Sperre durch alle diese Anrufe gehalten, anstatt für jeden Anruf freigegeben und erneut abgerufen zu werden.

+0

Ab Java 6 bedeutet Sperrvorspannung, dass die Erfassung einer nicht überwachten Sperre trotzdem schnell ist. –

+0

@ ChrisJester-Young - Ja, ich weiß nicht, wie relevant diese besondere Leistungsoptimierung noch ist (oder jemals war). – jtahlborn

+0

Ich nicht unterbewertet _ für jeden Anruf freigegeben und neu erworben_. Der 'write()' Aufruf versucht überhaupt nicht, auf dem 'Writer' zu 'synchronisieren'. Die Sperre wird nur einmal innerhalb der 'toString (int)' - Methode in der OP-Frage erworben und freigegeben. –

6

Der leere Konstruktor für StringWriter ist

/** 
* Create a new string writer using the default initial string-buffer 
* size. 
*/ 
public StringWriter() { 
    buf = new StringBuffer(); 
    lock = buf; 
} 

Nichts geteilt, deshalb ist die synchronized Block nicht erforderlich ist.

Es sei denn ... write Delegierten zu einem anderen Thread, aber ich bezweifle ernsthaft, dass.

1

getBuffer() liefert einen StringBuffer und entsprechend der Dokumentation a StringBuffer bereits synchronisiert:

String-Puffer für die Verwendung durch mehrere Threads sicher sind. Die Methoden werden bei Bedarf synchronisiert, sodass sich alle Vorgänge in einer bestimmten Instanz so verhalten, als ob sie in einer Reihenfolge auftreten, die der Reihenfolge der Methodenaufrufe der einzelnen beteiligten Threads entspricht.

Dies bedeutet, dass die erneute Synchronisierung auf dem StringBuffer völlig übertrieben ist. Änderungen an der StringWriter werden automatisch synchronisiert, da intern die synchronisierte StringBuffer verwendet wird.

Da die StringWriter Instanz lokal für den Methodenaufruf ist, ist es unmöglich, mehrere Threads gleichzeitig auf dieselbe Instanz zugreifen zu lassen, was ebenfalls die Synchronisation unnötig macht.

0

Es ist ein Fehler. Jeder Thread erstellt seine eigene lokale Variable in der Methode und synchronisiert sich darauf. Jedes Mal, wenn die Methoden-Threads eingegeben werden, erstellen sie ihren eigenen Objekt-Monitor, der nicht von einem anderen Thread gehalten werden kann, weil er lokal ist und nur auf dem Thread-Stack lebt.

Verwandte Themen