2009-03-10 15 views
13

Sto costruendo una stringa di più parti e voglio usare StringBuffer o StringBuilder per farlo. Dalle Java 5 documenti, vedo che StringBuilder è preferito quando possibile, con l'avvertenza cheJava StringBuilder e sicurezza thread

istanze di StringBuilder non sono sicure per i più thread.

Da questa affermazione, ho capito che non dovevo avere un unico StringBuilder istanza condivisa da più thread. Ma per quanto riguarda questo caso:

//Is this safe? 
//foo() is called simultaneously by multiple threads 
String foo(String a, String b) { 
    return new StringBuilder(a).append(b).toString(); 
} 

Qui ci potrebbero essere più filettature in funzione contemporaneamente, utilizzando la classe StringBuilder allo stesso tempo (ad esempio, l'accesso concorrente di variabili statiche, se ve ne sono), ma ogni thread avrebbe una propria istanza separata di StringBuilder. Dalla documentazione, non riesco a decidere se questo conta come se fosse usato da più thread o meno.

+0

potrebbe esserci qualche vantaggio nel rendere foo() anche un metodo statico, poiché non tocca alcuna variabile di istanza. – Kip

+0

@Kip: dipende dalla classe. Ma alcune volte potresti voler eseguire operazioni polimorfiche e rendere il metodo statico lo impedirà. – OscarRyz

+0

Utilizzare String.concat sarebbe più veloce, ma penso che questo sia solo un esempio. –

risposta

19

Questo va benissimo. Le variabili locali non hanno problemi con la sicurezza del thread, a condizione che non accedano o mutino variabili di istanza o classe.

11

Sì, questo è sicuro, perché l'oggetto StringBuilder viene utilizzato solo localmente (ogni thread che chiama foo() genererà il proprio StringBuilder).

Si dovrebbe inoltre notare che il codice che avete inviato è praticamente identico al bytecode generato da questo:

String foo(String a, String b) { 
    return a + b; 
} 
+0

Come vedi quel bytecode? – OscarRyz

+0

@Oscar: javap -c

+0

vedere anche: http://stackoverflow.com/questions/272535/how-do-i-decompile-java-class-files – Kip

4

d'accordo con le altre risposte - solo una nota.

Se esisteva un caso in cui StringBuffer veniva utilizzato da più thread, è probabilmente un caso d'uso completamente interrotto perché significherebbe che una singola stringa veniva creata in un ordine quasi casuale, quindi non avrebbe avuto senso rendere sicuro il thread StringBuffer.

+0

Questa è la logica di StringBuilder. La maggior parte delle volte la sincronizzazione non era necessaria. – OscarRyz

+0

Sì, il che ti fa chiedere perché non hanno appena riscritto StringBuffer invece di creare il StringBuilder parallelo. Per mantenere la retrocompatibilità per quell'app che costruisce stringhe non deterministiche? –

+1

Forse se stavi usando un StringBuilder per qualche tipo di registrazione in memoria di un'app multithreaded? Non so perché lo farebbe comunque ... – Kip

3

Non sono sicuro se questo codice è necessario, perché Java sceglie automaticamente lo StringBuilder. Se non si dispone di un problema di prestazioni, andare con un + b.

In caso di necessità prestazioni, provare che:

return new StringBuilder(
a.length() + b.length()).append(a).append(b).toString(); 

E formati correttamente il buffer e impedisce la VM di ridimensionare e creando spazzatura per raccogliere sulla strada.

6

Il codice che hai è sicuro.

Questo codice non è.

public class Foo 
{ 
    // safe 
    private final static StringBuilder builder; 

    public static void foo() 
    { 
     // safe 
     builder = new StringBuilder(); 
    } 

    public static void foo(final String a) 
    { 
     // unsafe 
     builder.append(a); 
    } 

    public synchronized void bar(final String a) 
    { 
     // safe 
     builder.append(a); 
    } 
} 

Le variabili locali che utilizzano solo dati locali non presentano problemi di tipo thread. È possibile avere problemi con il thread solo dopo aver iniziato a gestire i dati visibili alla classe o al metodo di istanza/livello di variabile.