2013-08-19 13 views
8

Nella libreria JSON-java (org.json.JSONArray) Ho trovato questo frammento di codice con un synchronized blocco attorno una variabile metodo localeNecessità di sincronizzato su variabile locale

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

Io non comprendono la necessità per la sincronizzazione qui, poiché StringWriter è solo locale al metodo specificato (e, perché la sincronizzazione è nel buffer). La sincronizzazione è davvero necessaria qui, e se, perché?

+8

Non è necessario. Con il costruttore predefinito, il buffer è un oggetto appena istanziato. 'buf = new StringBuffer();' all'interno del costruttore. –

+8

Si noti che l'autore della libreria org.json è un programmatore JavaScript, non un programmatore Java e questo fatto è dimostrato in tutto il codice. Per l'elaborazione JSON seria, prendi in considerazione l'utilizzo della libreria Gson di Google. –

risposta

7

Questo potrebbe essere un ottimizzazione delle prestazioni. Nell'oracle jvm, il re-acquisizione di un blocco già tenuto è molto veloce. Presumibilmente, la chiamata write sta effettuando numerose chiamate nello StringBuffer. Bloccando prima di chiamare write, il blocco verrà trattenuto attraverso tutte quelle chiamate anziché essere rilasciato e riacquisito per ciascuna chiamata.

+0

A partire da Java 6, il bias di blocco significa che l'acquisizione di un blocco non vincolato è comunque veloce. –

+0

@ ChrisJester-Young - sì, non so quanto sia rilevante (o lo sia mai stato) l'ottimizzazione delle prestazioni particolare. – jtahlborn

+0

Non ho sottovalutato _being rilasciato e riacquisito per ogni chiamata_. La chiamata 'write()' non prova affatto a 'synchronize' su' Writer'. Il blocco viene acquisito e rilasciato solo una volta, all'interno del metodo 'toString (int)' nella domanda dell'OP. –

6

La costruzione vuota StringWriter è

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

Nulla è condivisa, pertanto il blocco synchronized è inutile.

Salvo ... write delegati a un altro thread, ma ne dubito seriamente.

1

getBuffer() restituisce un StringBuffer, e secondo la documentazione una StringBuffer è già sincronizzato:

buffer stringa sono sicure per i più thread. I metodi sono sincronizzati dove necessario in modo che tutte le operazioni su una particolare istanza si comportino come se si presentassero in un ordine seriale coerente con l'ordine delle chiamate al metodo effettuate da ciascuno dei singoli thread coinvolti.

Ciò significa che la sincronizzazione di nuovo su StringBuffer è totalmente eccessivo. Le modifiche allo StringWriter verranno automaticamente sincronizzate poiché utilizzano lo StringBuffer sincronizzato internamente.

Poiché l'istanza StringWriter è locale alla chiamata del metodo, è impossibile avere più thread che accedono alla stessa istanza allo stesso tempo, il che rende la sincronizzazione non necessaria.

0

È un bug. Ogni thread crea la propria variabile locale nel metodo e si sincronizza su di esso. Ogni volta che si entra nel metodo, i thread creano il proprio object-monitor che non può essere tenuto da un altro thread perché è locale e vive solo sullo stack del thread!

Problemi correlati