批量方法调用的适当方法?

时间:2015-07-12 07:59:12

标签: java performance optimization

假设如下内容:

public boolean doThisThing(SomeArg arg) {
    if(iAmAllowedToDoIt()) {
        doThing(arg);
        return true;
    } else {
        return false;
    }

假设iAmAllowedToDoIt()是一个非常昂贵的方法,并且doThisThing()被许多线程同时调用,并且我被允许做任何事情,因为我被允许做任何事情,有没有办法批量调用iAmAllowedToDoIt ()这样我会在并发数据结构中积累SomeArgs,并且在解析iAmAllowedToDoIt一次而不修改API 后立即对所有这些进行doThing?那段代码会是什么样的?我无法弄清楚如何在不修改API 的情况下按照执行多线程批处理。理想的答案包括不依赖于在固定时间段内阻塞来积累doThisThing()的调用。

理想情况下,它最终会像:

  1. 致电doThisThing
  2. 异步调用iAmAllowedToDoIt
  3. 所有调用doThisThing之前(2)重新调整阻止直到(2)返回
  4. (2)如果为所有被阻止的doThisThing()s的真实调用doThing,则返回

2 个答案:

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