>  I'm not convinced that the memory is guaranteed to be available after the callback has returned, since the async code could (presumably) pick the thread up from the pool and use it to make another callback.

@agorrod The latest commit on this branch should address this issue.  After the notify() call returns, the AsyncOp's swigCptr is set to 0.  The effect is that any use of the Java AsyncOp from this point on will get NullPointerException.  So op.get*Key() or op.get*Value() is really restricted to the notify method.

Also I'm caching method ids and field ids.  And instead of a method call to invalidate the unpackers, I'm setting the fields directly via JNI.  I expect that is faster than the method call to resetResults(), but I have yet to measure it directly.