นากกายต้นฉบับกำลังรวมเมล็ดจากหลายรางนับเข้าสู่ถ้วยสรุปตรงกลาง

Java LongAdder: ลดการแย่ง counter ใน metrics แต่ห้ามใช้แทนเลขลำดับธุรกิจ

พี่โชว์Engineering

counter กลางตัวเดียวที่ทุก thread เพิ่มพร้อมกันอาจกลายเป็นจุดแย่ง cache line ครับ LongAdder กระจายการเพิ่มไปหลาย cell แล้วรวมเมื่อเรียก sum() จึงเหมาะกับ metrics ที่เขียนถี่และอ่านเป็นช่วง

import java.util.concurrent.atomic.LongAdder;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        LongAdder requests = new LongAdder();
        IntStream.range(0, 10_000).parallel().forEach(ignored -> requests.increment());
        assert requests.sum() == 10_000L;

        long drained = requests.sumThenReset();
        assert drained == 10_000L && requests.sum() == 0L;
        System.out.println("LongAdder tests passed");
    }
}

sum() ไม่ใช่ atomic snapshot ขณะที่มี update พร้อมกัน และ sumThenReset() อาจพลาด update หากใช้โดยไม่มีจุดประสาน จึงไม่เหมาะกับยอดเงิน, inventory, sequence ID หรือ quota ที่ต้องตัดสินใจจากค่าที่แม่นยำ ณ จุดเดียว กรณีนั้นใช้ AtomicLong, lock หรือ transaction ตาม invariant

Recap

  • ใช้ LongAdder กับ metric counter ที่ contention สูง
  • ยอมรับว่า sum() เป็นมุมมองระหว่างการอัปเดต
  • ห้ามใช้กับลำดับหรือยอดที่ต้อง atomic
  • benchmark ก่อนแทน AtomicLong ในระบบจริง