2013-08-19 10 views
8

W bibliotece JSON Java (org.json.JSONArray) Znalazłem ten fragment kodu z synchronized bloku wokół zmiennej metody lokalnegoKonieczność zsynchronizowane w zmiennej lokalnej

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

Nie rozumiem konieczność synchronizacji tutaj, ponieważ StringWriter jest tylko lokalny dla podanej metody (i dlaczego synchronizacja dotyczy bufora). Czy synchronizacja jest naprawdę potrzebna tutaj i jeśli, dlaczego?

+8

Nie jest to konieczne. Przy domyślnym konstruktorze bufor jest nowo utworzonym obiektem. 'buf = new StringBuffer();' wewnątrz konstruktora. –

+8

Należy zauważyć, że autor biblioteki org.json jest programistą JavaScript, a nie programistą Java, co zostało zademonstrowane w całym kodzie. W przypadku poważnego przetwarzania JSON rozważ użycie biblioteki Google Gson. –

Odpowiedz

7

Może to być optymalizacja wydajności. W wyroczni jvm, ponowne przejęcie już posiadanego zamka jest bardzo szybkie. Przypuszczalnie wywołanie write wywołuje wiele wywołań w StringBuffer. Blokując przed wywołaniem write, blokada będzie odbywać się przez wszystkie te połączenia zamiast być zwolnione i ponownie nabyte dla każdego połączenia.

+0

Począwszy od wersji Java 6, przesunięcie blokady oznacza, że ​​mimo to uzyskanie niekontrolowanej blokady jest szybkie. –

+0

@ ChrisJester-Young - tak, nie wiem, jakie znaczenie ma ta konkretna optymalizacja wydajności (lub kiedykolwiek była). – jtahlborn

+0

Nie ukrywam, że jestem zwolniony i ponownie pozyskany dla każdego call_. Wywołanie 'write()' nie próbuje i 'synchronizuje' na' Writer' w ogóle. Blokada zostaje pozyskana i zwolniona tylko raz, w metodzie 'toString (int)' w pytaniu OP. –

6

Pusty konstruktor StringWriter jest

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

Nic nie jest udostępniony, więc blok synchronized jest niepotrzebna.

O ile ... write nie deleguje do innego wątku, ale poważnie w to wątpię.

1

getBuffer() zwraca StringBuffer i zgodnie z dokumentacją StringBuffer jest już zsynchronizowane:

bufory strunowe są bezpieczne do użytku przez wiele wątków. Metody są zsynchronizowane w razie potrzeby, tak aby wszystkie operacje na konkretnej instancji zachowywały się tak, jakby występowały w jakiejś kolejności szeregowej zgodnej z kolejnością wywołań metod tworzonych przez każdy z poszczególnych wątków.

Oznacza to, że synchronizacja ponownie na StringBuffer jest całkowicie przesadzona. Zmiany w StringWriter zostaną automatycznie zsynchronizowane, ponieważ wewnętrznie używają zsynchronizowanego StringBuffer.

Ponieważ instancja StringWriter jest lokalna dla wywołania metody, niemożliwe jest posiadanie wielu wątków uzyskujących dostęp do tej samej instancji w tym samym czasie, co również powoduje, że synchronizacja jest niepotrzebna.

0

To jest błąd. Każdy wątek tworzy w metodzie swoją własną zmienną lokalną i synchronizuje ją. Każdy czas wprowadzania wątków metod tworzy własny monitor obiektu, który nie może być trzymany przez inny wątek, ponieważ jest lokalny i działa tylko na stosie wątku!

Powiązane problemy