Thread Interference / Race Condition
เกิดเมื่อ thread หลายตัว เข้าถึงและแก้ไข shared data พร้อมกัน โดยไม่มี synchronization ผลลัพธ์ขึ้นอยู่กับลำดับการรัน (non-deterministic)
ตัวอย่าง
class Counter {
static int value = 6;
void increment() {
for (int i = 0; i < 10; i++) {
value++;
System.out.println("Inc: " + value);
}
}
void decrement() {
for (int i = 0; i < 10; i++) {
value--;
System.out.println("Dec: " + value);
}
}
}
public class Demo {
public static void main(String[] args) {
Counter c = new Counter();
new Thread(c::increment).start();
new Thread(c::decrement).start();
}
}
ผลลัพธ์ (ตัวอย่าง - ไม่คงที่)
Inc: 7 Inc: 8 Dec: 7 Inc: 8 Dec: 7 ...
ปัญหา: value++ ไม่ใช่ atomic ประกอบด้วย 3 ขั้นตอน: Read → Modify → Write Thread อาจถูก interrupt ระหว่างขั้นตอน ทำให้ update หายไป
วิธีแก้
1. synchronized method
synchronized void increment() { ... }
synchronized void decrement() { ... }
2. synchronized block (fine-grained)
void increment() {
for (int i = 0; i < 10; i++) {
synchronized(this) { value++; }
}
}
3. AtomicInteger (lock-free, แนะนำ)
import java.util.concurrent.atomic.AtomicInteger;
class Counter {
AtomicInteger value = new AtomicInteger(6);
void increment() {
for (int i = 0; i < 10; i++) {
System.out.println("Inc: " + value.incrementAndGet());
}
}
// decrement: value.decrementAndGet()
}
สรุป
- Thread interference = Race condition บน shared mutable state
- แก้ด้วย synchronization (synchronized, Lock, Atomic classes)
- Atomic classes เร็วกว่า synchronized สำหรับ operation เรียบง่าย
- Immutable objects ป้องกันปัญหานี้ได้โดยรากฐาน