Java 如何以同步方式包装黑盒异步调用?
我在我的Android应用程序中使用了一个专有的第三方框架——具体来说,是Zebra的EMDK——以及他们公开的两种方法:Java 如何以同步方式包装黑盒异步调用?,java,android,asynchronous,concurrency,synchronization,Java,Android,Asynchronous,Concurrency,Synchronization,我在我的Android应用程序中使用了一个专有的第三方框架——具体来说,是Zebra的EMDK——以及他们公开的两种方法: .read()和.cancelRead()是异步的,每一个都需要一秒钟到5整秒钟的时间来完成。我需要能够在不破坏我的应用程序的情况下发送垃圾邮件,并确保每个邮件不会连续调用两次。我该怎么做呢?我无法访问这些方法本身,反编译器只会给我运行时存根 编辑:我也不知道这两个调用何时完成。可能会对此关闭,因为我无法100%确定您想要实现什么/或结构,但您能否将每个调用都包装在一个异步
.read()
和.cancelRead()
是异步的,每一个都需要一秒钟到5整秒钟的时间来完成。我需要能够在不破坏我的应用程序的情况下发送垃圾邮件,并确保每个邮件不会连续调用两次。我该怎么做呢?我无法访问这些方法本身,反编译器只会给我运行时存根
编辑:我也不知道这两个调用何时完成。可能会对此关闭,因为我无法100%确定您想要实现什么/或结构,但您能否将每个调用都包装在一个异步任务中?然后在父异步任务或后台线程中:
AsyncTask1.execute().get(); //get will block until complete
AsyncTask2.execute().get(); //get will block until complete
这是假设有某种方法可以知道您正在进行的调用已完成。将异步程序更改为阻塞程序是解决此问题的更一般要求 在Java中,我们可以使用
倒计时闩锁
(以及相位器
)或锁支持+原子
例如,如果需要将异步调用asyncDoSomethingAwesome(param,callback)
更改为阻塞调用,我们可以编写如下“包装器”方法:
ResultType doSomethingAwesome(ParamType param) {
AtomicReference<ResultType> resultContainer = new AtomicReference<>();
Thread callingThread = Thread.currentThread();
asyncDoSomethingAwesome(param, result -> {
resultContainer.set(result);
LockSupport.unpark(callingThread);
});
ResultType result;
while ((result = resultContainer.get()) == null) {
LockSupport.park();
}
return result;
}
不幸的是,我不知道他们什么时候完成。另外,我也可以通过使用信号量来实现您所做的,但是仍然不能保证其中一个方法不会被调用两次。只是看了一下文档。。。在不知道任何信息的情况下,是否可以从isReadPending()进行阻止-听起来似乎是判断是否正在运行read()的唯一方法?感谢您查看文档-不幸的是,它不可靠,原因很多,超出了我的问题范围。EMDK似乎充满了矛盾,我真的很想找到一种方法来保护其中的一些矛盾。正确处理异步是第一步:)如果
asyncDoSomethingAwesome
是黑盒并返回void
,该怎么办?不幸的是,我不知道我的异步方法何时完成,我无法编辑它们。对不起,我的意思是——如果asyncDoSomethingAwesome
没有回调怎么办?如果异步API不支持回调,并且我们无法重新设计它,那么得到通知的唯一方法就是重复查询结果(通常有一定的间隔)。但是,据我所知,这种方法通常不推荐用于单机系统,因为它效率低且复杂。如果我们能够重新挖掘API并允许它接受回调,事情就会简单得多。@grant park
ResultType doSomethingAwesome(ParamType param, Duration timeout) throws TimeoutException {
AtomicReference<ResultType> resultContainer = new AtomicReference<>();
Thread callingThread = Thread.currentThread();
asyncDoSomethingAwesome(param, result -> {
resultContainer.set(result);
LockSupport.unpark(callingThread);
});
ResultType result;
long deadline = Instant.now().plus(timeout).toEpochMilli();
while ((result = resultContainer.get()) == null) {
if (System.currentTimeMillis() >= deadline) {
throw new TimeoutException();
}
LockSupport.parkUntil(deadline);
}
return result;
}
ResultType doSomethingAwesome(ParamType param, Duration timeout) throws TimeoutException {
// We can use org.apache.commons.lang3.mutable.MutableObject instead of AtomicReference,
// because this object will never be accessed concurrently
MutableObject<ResultType> resultContainer = new MutableObject<>();
DisposableBlocker blocker = new DisposableBlocker();
asyncDoSomethingAwesome(param, result -> {
resultContainer.setValue(result);
blocker.unblock();
});
if (!blocker.blockFor(timeout)) {
throw new TimeoutException();
}
return resultContainer.getValue();
}