假设如下内容:
public boolean doThisThing(SomeArg arg) {
if(iAmAllowedToDoIt()) {
doThing(arg);
return true;
} else {
return false;
}
假设iAmAllowedToDoIt()是一个非常昂贵的方法,并且doThisThing()被许多线程同时调用,并且我被允许做任何事情,因为我被允许做任何事情,有没有办法批量调用iAmAllowedToDoIt ()这样我会在并发数据结构中积累SomeArgs,并且在解析iAmAllowedToDoIt一次而不修改API 后立即对所有这些进行doThing?那段代码会是什么样的?我无法弄清楚如何在不修改API 的情况下按照执行多线程批处理。理想的答案包括不依赖于在固定时间段内阻塞来积累doThisThing()的调用。
理想情况下,它最终会像:
答案 0 :(得分:0)
您的包含对象可能包含AtomicReference CompleteableFuture,用于计算incompatible types: Testcase.MapCollectorBuilder<String,String,Integer,CAP#1,ImmutableMap<String,Integer>> cannot be converted to Testcase.MapCollectorBuilder<String,String,Integer,Map<String,Integer>,ImmutableMap<String,Integer>>
where CAP#1 is a fresh type-variable:
CAP#1 extends Map<String,Integer> from capture of ? extends Map<String,Integer>
。 iAmAllowedToDoIt()
的其他调用只是等待可完成的未来的完成(如果存在),或者创建一个新的,具有适当的CAS循环以避免一次创建多个实例。
完成后,引用再次设置为null,以便稍后调用该方法的线程可以开始新的计算。
答案 1 :(得分:0)
您可以执行以下操作(实现类似于@ the8472提议的算法):
public class Test {
/**
* Lock used to guard accesses to allowedFuture
*/
private final Object lock = new Object();
/**
* The future result being computed, reset to null as soon as the result is known
*/
private FutureTask<Boolean> allowedFuture = null;
private static final Random RANDOM = new Random();
public boolean doThisThing() throws ExecutionException, InterruptedException {
if (iAmAllowedToDoIt()) {
System.out.println("doing it...");
return true;
}
else {
System.out.println("not doing it...");
return false;
}
}
private boolean iAmAllowedToDoIt() throws ExecutionException, InterruptedException {
// if true, this means that this thread is the one which must really compute if I am allowed
boolean mustCompute = false;
// The Future holding the result which is either the cached one, or a new one stored in the cache
FutureTask<Boolean> result;
synchronized (lock) {
// if no one has computed the result yet, or if it has been computed and thus must be recomputed
// then create it
if (this.allowedFuture == null) {
mustCompute = true;
this.allowedFuture = new FutureTask<>(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
System.out.println("computing if I am allowed...");
Thread.sleep(RANDOM.nextInt(3000));
boolean allowed = RANDOM.nextBoolean();
System.out.println(allowed ? "allowed!" : "not allowed!");
return allowed;
}
});
}
result = this.allowedFuture;
}
if (mustCompute) {
allowedFuture.run();
// reset the cache to null, so that the next thread recomputes the result
synchronized (lock) {
this.allowedFuture = null;
}
}
return result.get();
}
public static void main(String[] args) {
Test test = new Test();
Runnable r = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(RANDOM.nextInt(6000));
test.doThisThing();
}
catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
}
};
for (int i = 0; i < 50; i++) {
Thread t = new Thread(r);
t.start();
}
}
}