Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/202.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何以同步方式包装黑盒异步调用?_Java_Android_Asynchronous_Concurrency_Synchronization - Fatal编程技术网

Java 如何以同步方式包装黑盒异步调用?

Java 如何以同步方式包装黑盒异步调用?,java,android,asynchronous,concurrency,synchronization,Java,Android,Asynchronous,Concurrency,Synchronization,我在我的Android应用程序中使用了一个专有的第三方框架——具体来说,是Zebra的EMDK——以及他们公开的两种方法: .read()和.cancelRead()是异步的,每一个都需要一秒钟到5整秒钟的时间来完成。我需要能够在不破坏我的应用程序的情况下发送垃圾邮件,并确保每个邮件不会连续调用两次。我该怎么做呢?我无法访问这些方法本身,反编译器只会给我运行时存根 编辑:我也不知道这两个调用何时完成。可能会对此关闭,因为我无法100%确定您想要实现什么/或结构,但您能否将每个调用都包装在一个异步

我在我的Android应用程序中使用了一个专有的第三方框架——具体来说,是Zebra的EMDK——以及他们公开的两种方法:

.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();
}