import java.lang.invoke.VarHandle; import java.lang.invoke.MethodHandles; // assumes that each set function is called only once sclass PairCollector { volatile A a; volatile B b; volatile int counter; // statically get var handles private static final VarHandle vhA, vhB, vhCounter; static ctex { var l = MethodHandles.lookup(); vhA = l.findVarHandle(PairCollector.class, "a", O); vhB = l.findVarHandle(PairCollector.class, "b", O); vhCounter = l.findVarHandle(PairCollector.class, "counter", int.class); } void setA(A a) { this.a = a; incCounter(); } void setB(B b) { this.b = b; incCounter(); } IVF1 setterForA() { ret a -> setA(a); } IVF1 setterForB() { ret b -> setB(b); } private void incCounter() { if (((int) vhCounter.getAndAdd(this, 1))+1 == 2) complete(a, b); } // can override or swap swappable void complete(A a, B b) {} }