2016-03-15 12 views
9

Có trường hợp nào trong đó AtomicInteger.accumulateAndGet() không thể được thay thế bằng AtomicInteger.updateAndGet() hoặc chỉ là sự tiện lợi cho các tham chiếu phương pháp?Có bất kỳ sự khác biệt chức năng nào giữa AtomicInteger.updateAndGet() và AtomicInteger.accumulateAndGet() không?

Dưới đây là một ví dụ đơn giản mà tôi không thấy bất kỳ sự khác biệt chức năng:

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

Rõ ràng, cùng đi cho getAndUpdate()getAndAccumulate().

+2

Không phải là khả năng (tái) sử dụng các hàm hiện có (hoặc tham chiếu phương thức không bắt giữ) một tính năng hữu ích? Cũng không có sự khác biệt về chức năng giữa 'i.incrementAndGet()' và 'i.accumulateAndGet (1, Integer :: sum)'… – Holger

+0

@Holger 'accumulateAndGet()' được thêm vào sau, cộng với nó không thể sử dụng 'Unsafe'. 'addAndGet (1)' có thể là một ví dụ tốt hơn, nhưng thậm chí không sử dụng 'Unsafe' tại thời điểm nó được tạo ra. Tuy nhiên, tôi chấp nhận điểm chung của bạn; câu hỏi này chỉ là để làm rõ cho dù đó thực sự là động lực. – shmosel

Trả lời

4

Khi nghi ngờ, bạn có thể nhìn vào 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; 
} 

Họ chỉ khác nhau ở dòng duy nhất và rõ ràng accumulateAndGet có thể được thể hiện một cách dễ dàng thông qua updateAndGet:

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

Vì vậy updateAndGet phần nào cơ bản hơn hoạt động và accumulateAndGet là một phím tắt hữu ích. phím tắt như vậy có thể đặc biệt hữu ích nếu x của bạn không phải là một cách hiệu quả cuối cùng:

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

Có trường hợp một sự sáng tạo Ví dụ có thể tránh được bằng cách sử dụng accumulateAndGet.

Đây không phải là sự khác biệt thực sự nhưng có thể hữu ích khi biết.

Hãy xem xét ví dụ sau: sáng tạo

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); 
} 

Instance nói chung là không đắt tiền nhưng có thể là quan trọng để thoát khỏi trong hoạt động ngắn được sử dụng rất thường xuyên tại các địa điểm nhạy cảm hiệu suất.

Thông tin thêm về thời điểm sử dụng lại các cá thể lambda trong this answer.

Các vấn đề liên quan