2016-03-15 39 views
9

Esiste uno scenario in cui AtomicInteger.accumulateAndGet() non può essere sostituito con AtomicInteger.updateAndGet() o è solo una comodità per i riferimenti al metodo?Esiste una differenza funzionale tra AtomicInteger.updateAndGet() e AtomicInteger.accumulateAndGet()?

Ecco un semplice esempio in cui non vedo alcuna differenza funzionale:

AtomicInteger i = new AtomicInteger(); 
i.accumulateAndGet(5, Math::max); 
i.updateAndGet(x -> Math.max(x, 5)); 

Ovviamente, lo stesso vale per getAndUpdate() e getAndAccumulate().

+2

Non è la possibilità di (ri) utilizzare le funzioni esistenti (oi riferimenti ai metodi non acquisiti) una funzione utile? Non c'è inoltre alcuna differenza funzionale tra 'i.incrementAndGet()' e 'i.accumulateAndGet (1, Integer :: sum)' ... – Holger

+0

@Holger 'accumulateAndGet()' è stato aggiunto più tardi, inoltre non può usare 'Unsafe'. 'addAndGet (1)' potrebbe essere un esempio migliore, ma anche quello non stava usando 'Unsafe' nel momento in cui è stato creato. Tuttavia, accetto il tuo punto generale; questa domanda è solo per chiarire se questa fosse davvero la motivazione. – shmosel

risposta

4

In caso di dubbio, si può guardare in implementation:

public final int accumulateAndGet(int x, 
            IntBinaryOperator accumulatorFunction) { 
    int prev, next; 
    do { 
     prev = get(); 
     next = accumulatorFunction.applyAsInt(prev, x); 
    } while (!compareAndSet(prev, next)); 
    return next; 
} 

public final int updateAndGet(IntUnaryOperator updateFunction) { 
    int prev, next; 
    do { 
     prev = get(); 
     next = updateFunction.applyAsInt(prev); 
    } while (!compareAndSet(prev, next)); 
    return next; 
} 

Essi differiscono solo per singola linea e, ovviamente, accumulateAndGet potrebbe essere espresso in modo semplice via updateAndGet:

public final int accumulateAndGet(int x, 
            IntBinaryOperator accumulatorFunction) { 
    return updateAndGet(prev -> accumulatorFunction.applyAsInt(prev, x)); 
} 

Così updateAndGet è un po 'più di base operazione e accumulateAndGet è una scorciatoia utile. Tale collegamento potrebbe essere particolarmente utile se il vostro x non è efficace finale:

int nextValue = 5; 
if(something) nextValue = 6; 
i.accumulateAndGet(nextValue, Math::max); 
// i.updateAndGet(prev -> Math.max(prev, nextValue)); -- will not work 
1

Ci sono casi in cui una creazione istanza può essere evitato utilizzando accumulateAndGet.

Questa non è una differenza funzionale ma potrebbe essere utile sapere.

consideri il seguente esempio: creazioni

void increment(int incValue, AtomicInteger i) { 
    // The lambda is closed over incValue. Because of this the created IntUnaryOperator 
    // will have a field which contains incValue. Because of this a new instance must 
    // be allocated on every call to the increment method. 
    i.updateAndGet(value -> incValue + value); 

    // The lambda is not closed over anything. The same IntBinaryOperator instance 
    // can be used on every call to the increment method, nothing need to be allocated. 
    i.accumulateAndGet(incValue, (incValueParam, value) -> incValueParam + value); 
} 

istanza non sono generalmente costosi, ma può essere importante per sbarazzarsi di nelle operazioni brevi che vengono utilizzati molto frequentemente in luoghi sensibili prestazioni.

Ulteriori informazioni su quando vengono riutilizzate le istanze lambda sono disponibili in this answer.