gpt4 book ai didi

jsf - 在 Java EE 中手动启动新线程安全吗?

转载 作者:行者123 更新时间:2023-12-03 06:21:37 26 4
gpt4 key购买 nike

对于在 session 范围的 JSF 托管 bean 中生成线程是否安全,我找不到明确的答案。该线程需要调用无状态 EJB 实例(依赖注入(inject)到托管 bean)上的方法。

背景是我们有一份报告需要很长时间才能生成。由于我们无法更改服务器设置,这导致 HTTP 请求超时。所以想法是启动一个新线程并让它生成报告并暂时存储它。同时,JSF 页面显示一个进度条,轮询托管 bean 直到生成完成,然后发出第二个请求来下载存储的报告。这似乎有效,但我想确定我所做的不是黑客行为。

最佳答案

查看 EJB 3.1 @Asynchronous methods 。这正是它们的用途。

使用 OpenEJB 4.0.0-SNAPSHOT 的小示例。这里我们有一个@Singleton具有标记为 @Asynchronous 的一种方法的 bean 。每当任何人(在本例中是 JSF 托管 bean)调用该方法时,无论该方法实际需要多长时间,它都会立即返回。

@Singleton
public class JobProcessor {

@Asynchronous
@Lock(READ)
@AccessTimeout(-1)
public Future<String> addJob(String jobName) {

// Pretend this job takes a while
doSomeHeavyLifting();

// Return our result
return new AsyncResult<String>(jobName);
}

private void doSomeHeavyLifting() {
try {
Thread.sleep(SECONDS.toMillis(10));
} catch (InterruptedException e) {
Thread.interrupted();
throw new IllegalStateException(e);
}
}
}

这是一个调用 @Asynchronous 的小测试用例方法连续多次。

每次调用都会返回 Future本质上开始时为空的对象,稍后当相关方法调用实际完成时,其值将由容器填充。

import javax.ejb.embeddable.EJBContainer;
import javax.naming.Context;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class JobProcessorTest extends TestCase {

public void test() throws Exception {

final Context context = EJBContainer.createEJBContainer().getContext();

final JobProcessor processor = (JobProcessor) context.lookup("java:global/async-methods/JobProcessor");

final long start = System.nanoTime();

// Queue up a bunch of work
final Future<String> red = processor.addJob("red");
final Future<String> orange = processor.addJob("orange");
final Future<String> yellow = processor.addJob("yellow");
final Future<String> green = processor.addJob("green");
final Future<String> blue = processor.addJob("blue");
final Future<String> violet = processor.addJob("violet");

// Wait for the result -- 1 minute worth of work
assertEquals("blue", blue.get());
assertEquals("orange", orange.get());
assertEquals("green", green.get());
assertEquals("red", red.get());
assertEquals("yellow", yellow.get());
assertEquals("violet", violet.get());

// How long did it take?
final long total = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);

// Execution should be around 9 - 21 seconds
assertTrue("" + total, total > 9);
assertTrue("" + total, total < 21);
}
}

Example source code

这项工作的幕后原因是:

  • JobProcessor调用者看到的实际上并不是 JobProcessor 的实例。相反,它是重写所有方法的子类或代理。应该是异步的方法的处理方式有所不同。
  • 调用异步方法只会导致 Runnable正在创建包装您提供的方法和参数。该可运行对象被赋予 Executor它只是一个附加到线程池的工作队列。
  • 将工作添加到队列后,该方法的代理版本返回 Future 的实现链接到 Runnable现在正在队列中等待。
  • Runnable最后在真实上执行该方法 JobProcessor例如,它将获取返回值并将其设置为 Future使其可供调用者使用。

重要的是要注意 AsyncResult反对JobProcessor返回不一样Future调用者持有的对象。如果是真的 JobProcessor 那就太好了可以返回 String以及调用者的 JobProcessor 版本可以返回Future<String> ,但我们没有找到任何方法可以在不增加更多复杂性的情况下做到这一点。所以AsyncResult是一个简单的包装对象。容器将拉出 String出去,扔掉AsyncResult走,然后把 String真实 Future调用者所持有的。

要取得进展,只需传递一个线程安全对象,如 AtomicInteger@Asynchronous方法并让 bean 代码定期更新它的完成百分比。

关于jsf - 在 Java EE 中手动启动新线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6149919/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com