我正在我的Android应用程序中使用专有的第三方框架-具体来说是Zebra的EMDK-及其使用的两种公开方法:
.read()
和.cancelRead()
是异步的,每个过程花费一秒钟到5整秒的时间。我需要能够向他们发送垃圾邮件而不会崩溃我的应用程序,并确保每个行都不会被两次调用。我该怎么做呢?我本身没有方法的访问权限,反编译器只会给我运行时存根。
编辑:我也不知道这两个调用何时完成。
答案 0 :(得分:1)
将异步程序更改为阻塞程序是解决此问题的更普遍要求。
在Java中,我们可以使用CountDownLatch
(以及Phaser
)或LockSupport + Atomic
来做到这一点。
例如,如果需要将异步调用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;
}
我认为这足以解决您的问题。但是,在编写阻塞程序时,即使底层接口不能正常工作,我们通常也希望“超时”来保持系统稳定,例如:
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;
}
有时,我们需要对线程之间的信号进行更精细的管理,尤其是在编写并发库时。例如,当我们需要知道阻塞线程是否从另一个调用LockSupport.unpark
的线程接收到信号,或者该线程是否成功通知了阻塞线程时,使用Java标准库通常不容易实现。因此,我设计了另一个具有更完善机制的库来解决此问题:
https://github.com/wmx16835/experimental_java_common/blob/master/alpha/src/main/java/mingxin/wang/common/concurrent/DisposableBlocker.java
在DisposableBlocker
的支持下,生活将变得更加轻松:)
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();
}
答案 1 :(得分:0)
可能不建议这样做,因为我不能100%地确定您要实现什么/也不需要该结构,但是可以将它们包装在AsyncTask中吗?然后在父级AsyncTask或后台线程中:
AsyncTask1.execute().get(); //get will block until complete
AsyncTask2.execute().get(); //get will block until complete
这是假设您可以通过某种方式知道您正在完成的通话。