我有一个 Java UI 服务,它有一个 API 方法,该方法调用一个相对较慢的操作(比如大约 30 秒)。该操作是无参数的,但它对随时间变化(相对缓慢)的外部数据进行操作。该方法返回最新结果并不重要 - 如果它们是 30 秒的旧结果,那就可以接受。
最终,我需要优化慢速操作的实现,但作为短期修复,我想让该操作互斥,这样,如果第二个传入请求(在单独的线程上)尝试调用该操作,而另一个已经在进行中,然后第二个会阻塞,直到第一个完成为止。然后,第二个线程使用第一次调用该操作的结果 - 即它不会尝试再次运行该操作。
E.g.:
class MyService {
String serviceApiMmethod() {
// If a second thread attempts to call this method while another is in progress
// then block here until the first returns and then use those results
// (allowing it to return immediately without a second call to callSlowOperation).
return callSlowOperation();
}
}
Java (8) 中首选的通用方法是什么?我猜我可以使用 CountDownLatch,但尚不清楚如何最好地跨线程共享结果。是否有现有的并发原语可以促进这一点?
EDIT:一旦所有线程都消耗了结果(即将其返回给调用者),我需要清除对结果的任何引用,因为它是相对较大的对象,需要尽快进行 GC。
简单的想法
版本1:
class Foo {
public String foo() throws Exception {
synchronized (this) {
if (counter.incrementAndGet() == 1) {
future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000 * (ThreadLocalRandom.current().nextInt(3) + 1));
} catch (InterruptedException e) {
}
return "ok" + ThreadLocalRandom.current().nextInt();
});
}
}
String result = future.get();
if (counter.decrementAndGet() == 0) {
future = null;
}
return result;
}
private AtomicInteger counter = new AtomicInteger();
private Future<String> future;
}
版本 2:与@AleksandrSemyannikov 一起
public class MyService {
private AtomicInteger counter = new AtomicInteger();
private volatile String result;
public String serviceApiMethod() {
counter.incrementAndGet();
try {
synchronized (this) {
if (result == null) {
result = callSlowOperation();
}
}
return result;
} finally {
if (counter.decrementAndGet() == 0) {
synchronized (this) {
if (counter.get() == 0) {
result = null;
}
}
}
}
}
private String callSlowOperation() {
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
return Thread.currentThread().getName();
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)