Domanda

In Java, assegnazione è atomico se la dimensione della variabile è inferiore o uguale a 32 bit, ma non se più di 32 bit.

Cosa (volatile / sincronizzato) sarebbe più efficiente usare in caso di assegnazione doppia o lunghi?

Come,

  volatile double x = y;

sincronizzato non è applicabile con l'argomento primitiva. Come faccio un utilizzo sincronizzato in questo caso? Certo che non voglio bloccare la mia classe, in modo this non deve essere utilizzato.

È stato utile?

Soluzione

Se si trova il blocco sull'oggetto in sé troppo pesante, quindi sincronizzato è la strada da percorrere. Prima di Java 1.5 volatili può essere stata una buona scelta, ma ora volatili può avere un impatto molto grande forzando istruzioni ordinamento sul metodo in cui l'assegnazione avviene. Creare un oggetto separato (private final Object X_LOCK = new Object();) e sincronizzare su di esso quando si imposta o di ottenere il valore di quel doppio. Questo vi darà un buon livello di controllo sul blocco, che sembra che vi serve.

Nel nuovo pacchetto di concorrenza ci sono più opzioni, come ad esempio AtomicReference che può essere un buon sostituto per volatili, se si ha realmente bisogno per evitare la sincronizzazione.

Altri suggerimenti

Che cosa stai cercando di fare? I synchronized e volatile parole chiave sono meccanismi in Java che possono essere utilizzate per garantire che i valori costanti sono osservati da diversi fili leggendo gli stessi dati. In particolare, essi consentono di ragionare su accade-prima i rapporti nei vostri programmi.

Semplicemente non si può evitare di usare uno dei volatile o synchronized al fine di accedere correttamente campi non final in un programma multi-threaded. Detto questo, il motivo principale che si rischia di richiedere synchronized sopra volatile è il requisito per l'utilizzo atomica confrontare e impostare le operazioni (vale a dire non sarà alcuna considerazione le prestazioni ). Ad esempio, in un programma multi-threaded:

volatile int i = 0;

public void foo() { 
    if (i == 0) i = i + 1;
}

Il codice sopra è intrinsecamente pericolosi, anche se la dichiarazione della variabile come mezzi volatili che legge e scrive sono svuotate alla memoria principale - l'unica implementazione sicura di un tale metodo sarebbe qualcosa come:

int i = 0;

public synchronized void foo() {
    if (i == 0) i = i + 1;
}

Quindi, quale se preferite? Beh, se si dispone di più thread modifica di un campo dipende dal valore di campo (cioè confrontare-e set), quindi synchronized è l'unica soluzione sicura.

E 'anche la pena dire: il sovraccarico delle prestazioni di synchronized non è un problema (nella stragrande maggioranza dei casi). problemi di sincronizzazione prestazioni sono di solito a causa di colli di bottiglia di codice inutili, situazioni di stallo o livelocks e possono essere mitigati se necessario. Qualsiasi puri orologio-cicli in testa sarà sminuito da altre cose che l'applicazione fa:. File IO, query di database, etc Remoting

volatili è sicuramente la strada da percorrere se si sta solo facendo un incarico. Sono sicuro che sai, ma da quando è stato allevato: se si desidera fare operazioni più complesse (incrementare il valore per esempio) si avrebbe bisogno di syncrhonize. i ++ è mai infilare sicuro per ogni tipo di variabile. È necessario sincronizzare. i ++ e simili poiché questo è effettivamente più di 1 operazione.

Non: E 'stato espresso che si potrebbe usare AtomicDouble ma al momento non c'è AtomicDouble in java.util.concurrent.atomic

Se si sta facendo un più operazioni su x, che richiede l'impostazione a un nuovo valore, alla fine, è possibile farlo in modo sicuro filo senza bloccaggio cosa così mai, e lo hanno essere thread-safe, utilizzando confrontare e impostare. Esempio:

AtomicLong x = new AtomicLong(SomeValue);
public void doStuff() {
  double oldX;
  double newX;
  do {
    oldX = x.get();
    newX = calculateNewX(oldX);
  } while (!x.compareAndSet
      (Double.doubleToLongBits(oldX), Double.doubleToLongBits(newX)));

Questo funziona perché compareAndSet vedrà se il valore di x è cambiato dall'ultima volta che lo si legge. Se x è cambiato allora si è costretti a fare il calcolo di nuovo e ri-provare con un valore.

Si potrebbe, naturalmente, implementare il proprio AtomicDouble invece di fare queste doubleToLongBits conversioni. Date un'occhiata a AtomicFieldUpdater.

KDSRathore, è possibile utilizzare alcuni blocchi espliciti, o fare qualche oggetto fittizio Object = new Object (), sul quale si sincronizza in setter / getter di quel doppio

la documentazione di Oracle , è possibile utilizzare volatile per riferirsi a doppio oggetto:

volatile Double x = y;

"scrive e legge di riferimenti sono sempre atomica, a prescindere dal fatto che siano implementati come valori a 32 bit o 64-bit."

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top