นากแม่น้ำต้นฉบับยืนที่แท่นกลางแลกตะกร้าสองใบซึ่งมาจากคนละสายพาน

Java Exchanger: นัดแลกข้อมูลระหว่างสองงานแบบเจอกันพอดี

พี่โชว์Engineering

งานสองตัวที่ต้องส่งของให้กันตรงจังหวะ เช่น producer ส่ง batch เต็มและรับ buffer ว่างกลับมา ใช้ Exchanger เป็นจุดนัดพบแบบสองฝ่ายได้ครับ ทั้งคู่เรียก exchange แล้วรอจนคู่ของมันมาถึง

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Main {
  public static void main(String[] args) throws Exception {
    Exchanger<String> exchanger = new Exchanger<>();
    ExecutorService pool = Executors.newFixedThreadPool(2);
    try {
      Future<String> left = pool.submit(
          () -> exchanger.exchange("full-batch", 1, TimeUnit.SECONDS));
      Future<String> right = pool.submit(
          () -> exchanger.exchange("empty-buffer", 1, TimeUnit.SECONDS));

      assert left.get().equals("empty-buffer");
      assert right.get().equals("full-batch");
    } finally {
      pool.shutdownNow();
    }
  }
}

เหมือนคนส่งอาหารสองฝั่งสะพานต้องมาถึงจุดกลางก่อนจึงสลับตะกร้าได้ จุดแข็งคือไม่มี mailbox ค้างอยู่ แต่ถ้าฝ่ายหนึ่งล้ม อีกฝ่ายอาจรอไม่จบ จึงควรใช้ overload ที่มี timeout และกำหนดว่าจะ retry, abort หรือคืน buffer อย่างไร

Exchanger เหมาะกับสอง party ต่อหนึ่งรอบ ถ้ามี producer/consumer หลายตัว ต้อง buffer งาน หรืออยากเลือกคนรับแบบยืดหยุ่น BlockingQueue มักตรงกว่า อย่าใช้เพียงเพราะชื่อดู concurrent ครับ

Recap

  • ใช้กับการแลกข้อมูลแบบสองฝ่าย
  • ตั้ง timeout แทนการรอไม่สิ้นสุด
  • ออกแบบ recovery เมื่อคู่แลกถูกยกเลิก
  • ใช้ queue เมื่อ topology มีหลายฝ่ายหรือจำเป็นต้อง buffer