import java.lang.invoke.*;
public class AlmostFinal<T> {
private final MethodHandle getter;
private SwitchPoint switchPoint;
private VolatileCallSite callSite;
public AlmostFinal(T initial) {
switchPoint = new SwitchPoint();
callSite = new VolatileCallSite(MethodType.genericMethodType(0));
getter = switchPoint.guardWithTest(MethodHandles.constant(Object.class, initial), callSite.dynamicInvoker());
}
public T value() {
try {
return (T) getter.invokeExact();
} catch (Throwable t) {
throw new Error(t); // Shouldn't happen
}
}
public synchronized void setValue(T val) {
final SwitchPoint[] invalid = { switchPoint };
switchPoint = new SwitchPoint();
final VolatileCallSite previousSite = callSite;
callSite = new VolatileCallSite(MethodType.genericMethodType(0));
previousSite.setTarget(switchPoint.guardWithTest(MethodHandles.constant(Object.class, val), callSite.dynamicInvoker()));
SwitchPoint.invalidateAll(invalid);
}
}