2012-09-03 14 views
14

Per quanto ne so che java.util.Date è modificabile, quindi non è thread-safe se più thread hanno provato ad accedere e modificarlo. Come utilizziamo il locking o la composizione lato client (wrapper) per renderlo thread-safe?Come rendere Java.util.Date thread-safe

+4

Se siamo già qui, 'GregorianCalendar' e' SimpleDateFormat' non sono thread-safe. Vale sempre la pena ricordare. –

+0

Grazie per aver ricordato – peter

risposta

28

in questo ordine, dal migliore al peggiore:

  1. non si usa affatto, controlla

  2. non si usa affatto, utilizzare AtomicLong o immutabile primitiva long con volatile di rappresentare tempo epoca

  3. Incapsulare. Restituire sempre la copia difensiva di Date, mai un riferimento all'oggetto interno

  4. Sincronizzare sull'istanza Date.

+0

Mi chiedo perché hai considerato il 2 ° migliore del 3 °? – peter

+2

@ user1389813: Buona domanda! 1. I primitivi sono immutabili e quindi implicitamente sicuri del thread. 2. Non è possibile, per coincidenza, restituire il riferimento all'oggetto interno anziché una copia difensiva. 3. Più leggero, meno copia (non proprio un grosso problema). Comunque sono d'accordo, 2 e 3 sono entrambi abbastanza buoni. Anche ovviamente 'Date' ha una semantica migliore di' long'. –

+0

Vedo. Il secondo punto ti serve la guardia con un lucchetto vero? come @dystroy ha sottolineato che l'operazione di incremento non è atomica. – peter

-1

Non esiste una soluzione semplice per creare un wrapper thread-safe della classe Date. Il modo migliore è sincronizzare tutti gli usi degli oggetti utilizzando i blocchi synchronized.

+0

Quindi devi portare quel blocco di sincronizzazione ovunque lo usi. Non è buono nella pratica? – peter

+0

È terribile nel codice. Questo è il motivo per cui Tomasz risponde è molto meglio del mio;) –

2

La soluzione più semplice è non modificare mai una data e non condividerla mai. Ad esempio, utilizza solo la data per le variabili locali.

È possibile utilizzare JodaTime in quanto ha oggetti di data immutabili.

3

È possibile utilizzare il valore lungo (millisecondi da Epoch) anziché un'istanza Date. Assegnarlo sarà un'operazione atomica e sarebbe sempre coerente.

Ma il tuo problema forse non è sul valore Data stesso ma sull'intero algoritmo, il che significa che la risposta reale sarebbe basata sul tuo vero problema.

Ecco un esempio di un'operazione buggy in un contesto multithread:

long time; 
void add(long duration) { 
    time += duration; 
} 

Il problema qui è che si può avere due aggiunte in parallelo con conseguente sola aggiunta efficace, perché time += duration non è atomica (è davvero time=time+duration).

L'utilizzo di un oggetto lungo anziché normale non è sufficiente. In questo caso è possibile risolvere il problema impostando la funzione come sincronizzata, ma altri casi potrebbero essere più complicati.

+0

Cosa intendi per 'il tuo problema forse non è sul valore dei dati stessi ma sull'intero algoritmo – peter

+0

Se tu? Stai facendo una lunga operazione iniziando leggendo la data e finendo sostituendo il valore. Il blocco del valore durante l'operazione potrebbe farlo. –

+0

aiuterà a renderlo volatile? – peter