นากกายต้นฉบับปิดวาล์วทรัพยากรด้วยมือ ขณะที่สายสำรองต่อเข้ากลไกปิดอัตโนมัติ

Java Cleaner: มี fallback cleanup แต่ยังต้องปิด resource แบบ explicit

พี่โชว์Engineering

wrapper ของ native handle อาจต้องมี safety net หาก caller ลืม close() ครับ java.lang.ref.Cleaner ลงทะเบียน cleaning action ที่เรียกได้ทั้ง explicit และเมื่อ owner phantom-reachable แต่จังหวะอัตโนมัติไม่แน่นอน

WHY: ทางหนีไฟไม่ใช่ประตูเข้าออกประจำ

try-with-resources คือประตูหลักที่ปิดตรงเวลา Cleaner คือทางหนีไฟเมื่อ contract ถูกละเมิด หากผูก connection pool, lock หรือ quota กับเวลาของ GC ระบบอาจ resource หมดก่อน cleaner ได้ทำงาน จึงต้อง expose close() และให้ test ใช้เส้น explicit

import java.lang.ref.Cleaner;
import java.util.concurrent.atomic.AtomicInteger;

public class Main implements AutoCloseable {
  private static final Cleaner CLEANER = Cleaner.create();

  private static final class State implements Runnable {
    private final AtomicInteger releases;
    State(AtomicInteger releases) { this.releases = releases; }
    public void run() { releases.incrementAndGet(); }
  }

  private final Cleaner.Cleanable cleanable;

  Main(AtomicInteger releases) {
    this.cleanable = CLEANER.register(this, new State(releases));
  }

  @Override public void close() {
    cleanable.clean();
  }

  public static void main(String[] args) {
    AtomicInteger releases = new AtomicInteger();
    Main resource = new Main(releases);
    resource.close();
    resource.close();
    assert releases.get() == 1 : releases;
  }
}

Cleaning action ห้ามถือ owner กลับมา

ถ้า State เป็น non-static inner class มันถือ reference ไปยัง owner ทำให้ owner ไม่ถึงสถานะที่ cleaner รอ เอกสารจึงแนะนำ state object แยกที่เก็บเฉพาะข้อมูลจำเป็น Action ต้อง idempotent, เร็ว และไม่พึ่งลำดับกับ cleaner ของ object อื่น

อย่าเรียก System.gc() เพื่อบังคับ correctness และอย่าใช้ Cleaner แทน transaction rollback หาก cleanup ล้ม ควรมี metric/log ที่ไม่เปิดเผย secret และมี operational recovery สำหรับ resource ภายนอก

Recap

  • ใช้ AutoCloseable กับ try-with-resources เป็นเส้นทางหลัก
  • Cleaner เป็น safety net ที่เวลาไม่แน่นอน
  • state/action ต้องไม่ถือ owner กลับมา
  • ทำ cleanup ให้ idempotent และตรวจ explicit path ใน test