Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Java

Memory Consistency Error ใน Java Multithreading

Memory Consistency Error คืออะไร?

เมื่อ thread หลายตัวเข้าถึง shared data การเปลี่ยนแปลงของ thread หนึ่งอาจ ไม่มองเห็น โดย thread อีกตัว ทำให้มุมมองข้อมูลไม่สอดคล้อง (inconsistent view)

สาเหตุหลัก

  • CPU Cache: แต่ละ core มี cache (L1/L2) ของตัวเอง เขียนค่าใหม่อาจอยู่ใน cache ยังไม่ flush ไป main memory
  • Reordering: Compiler/CPU จัดลำดับคำสั่งใหม่เพื่อประสิทธิภาพ (instruction reordering)
  • Non-atomic operations: การอ่าน/เขียน 64-bit (long/double) บนบาง architecture ไม่ใช่ atomic

ตัวอย่าง: Race Condition + Visibility Problem


class Shared {
    static int counter = 0;
    
    void increment() {
        for (int i = 0; i < 5; i++) {
            counter++;
            System.out.println("Inc: " + counter);
        }
    }
    
    void decrement() {
        for (int i = 0; i < 5; i++) {
            counter--;
            System.out.println("Dec: " + counter);
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        Shared shared = new Shared();
        
        Thread t1 = new Thread(shared::increment);
        Thread t2 = new Thread(shared::decrement);
        
        t1.start();
        t2.start();
    }
}

ผลลัพธ์ (ไม่คงที่ - race condition)

Inc: 1
Dec: 0
Dec: -1
Inc: 0
Inc: 1
Dec: 0
Inc: 2
Dec: 1
Dec: 0
Inc: 1

วิธีแก้: Happens-Before Relationship

สร้าง happens-before เพื่อรับประกัน visibility:

  • Thread.start() → happens-before ทุก action ใน thread ใหม่
  • Thread.join() → happens-before หลัง thread จบ
  • volatile variable: write happens-before read
  • synchronized: unlock happens-before lock
  • AtomicInteger, ConcurrentHashMap etc.

แก้ตัวอย่างด้วย volatile


class Shared {
    volatile static int counter = 0; // volatile!
    // ... methods ...
}

หมายเหตุ: volatile แก้ visibility แต่ ไม่แก้ atomicity ของ counter++ (read-modify-write) ต้องใช้ AtomicInteger หรือ synchronized ร่วมด้วย