我正在尝试从 EJB 异步进程中获取进度百分比。这可能吗?
有谁知道我该怎么做?
了解异步进程的进度总是很棘手,特别是如果您不知道它们是否真正开始了。
我发现的最好方法是编写另一个只获取进度的函数,因此,如果每次调用都有一些唯一的 id,则hashmap
使用当前进程更新 a 。您可能想查看并发哈希图(http://download-llnw.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentHashMap.html)
然后这个其他查找函数将只获取唯一 ID,并将进度返回给客户端。
如果它尚未启动,您也可以返回它,理想情况下,您可能还希望能够返回处理过程中出现的任何错误消息。
然后,当它完成后,您返回错误消息或成功,然后将其从 hashmap 中删除,客户端获取信息,并且该信息不会更改,因此保留它没有意义。
更新:
在您的界面中创建一个新功能
String progressDone(String id);
然后您将同步引用它,因为它只是出去然后马上回来,因此它可以id
在其中查找hashmap
并返回完成百分比或错误消息。
但是,这意味着你的实际工作函数需要时常在 hashmap 中放置关于它在哪里的信息,这就是我建议使用并发 hashmap 的原因,这样你就不必担心并发写入,所以锁定注意事项。
我找到的解决方案是异步方法和主线程之间共享的上下文对象。这是一个例子:
异步作业本身:
@Stateless
public class AsyncRunner implements AsyncRunnerLocal {
@Asynchronous
public Future<ResultObject> doWorkAsynchronous(WorkContext context) {
context.setRunning(true);
for (int i = 0; i < 100; i++) {
//Do the next iteration of your work here
context.setProgress(i);
}
context.setRunning(false);
return new AsyncResult(new ResultObject());
}
}
共享上下文对象。这里重要的是 volatile 关键字。字段值将在没有它的每个线程中本地缓存,并且在主线程中将看不到进度:
public class WorkContext {
//volatile is important!
private volatile Integer progress = 0;
private volatile boolean running = false;
//getters and setters are omitted
}
使用示例:
public class ProgressChecker {
@EJB
private AsyncRunnerLocal asyncRunner;
private WorkContext context;
private Future<ResultObject> future;
public void startJob() {
this.context = new WorkContext();
future = asyncRunner.doWorkAsynchronous(this.context);
//the job is running now
while (!future.isDone()) {
System.out.println("Progress: " + this.context.getProgress());
Thread.sleep(1000); //try catch is omitted
}
}
}
在 EJB3.1中,@Asynchronous方法调用可以返回java.util.concurrent.Future,此接口提供信息boolean isCancelled()或boolean isDone(),但不提供执行是否开始的信息。在我看来,如果流程以标准方式通过 EJB-Container 开始执行,则无法获取信息。