java - util - spring executorservice example




使用ExecutorService與任務樹執行 (2)

Java 7具有ForkJoinPool的概念,允許任務通過將任務提交給相同的執行程序來“分離”另一個任務。 然後給它一個選項,稍後嘗試通過嘗試運行它來“幫助加入”該任務,如果它尚未運行。

我相信通過簡單地將ExecutorFutureTask相結合,Java 6中也可以做到同樣的事情。 像這樣:

public class Fib implements Callable<Integer> {
    int n;
    Executor exec;

    Fib(final int n, final Executor exec) {
        this.n = n;
        this.exec = exec;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Integer call() throws Exception {
        if (n == 0 || n == 1) {
            return n;
        }

        //Divide the problem
        final Fib n1 = new Fib(n - 1, exec);
        final Fib n2 = new Fib(n - 2, exec);

        //FutureTask only allows run to complete once
        final FutureTask<Integer> n2Task = new FutureTask<Integer>(n2);
        //Ask the Executor for help
        exec.execute(n2Task);

        //Do half the work ourselves
        final int partialResult = n1.call();

        //Do the other half of the work if the Executor hasn't
        n2Task.run();

        //Return the combined result
        return partialResult + n2Task.get();
    }

}        

我們有一個問題。 :)

我們希望確保只有N個線程隨時都在執行後台任務。 為此,我們使用了一個固定的線程池執行器。 它似乎工作正常。

然後我們發現了一個問題。 假設你有一個類,它使用執行器來做一些並行的工作,然後在執行器線程中調用其他一些類,這個線程也做了一些並行的工作,打算等待它。 以下是發生的事情:

  • 主線程調用一級方法。
  • 這個方法認為它可以並行化為16個任務並分解它的工作。
  • 執行者提交了16項任務。
  • 主線程開始等待其任務完成。
  • 假設有四個線程可用,前四個任務每個都被拾取並運行。 所以隊列中還剩下12個任務。
  • 現在,其中一個任務調用其他方法。
  • 這個新方法認為它可以並行化為2個任務。 假設這是並行合併排序的第一步,或者沿著這些線路進行的。
  • 2個任務被提交給執行者。
  • 此線程現在開始等待其任務完成。

嗯,哦。 所以在這一點上,所有四個線程現在將等待任務完成,但他們正在協同阻止執行者實際運行這些任務。

此問題的解決方案1如下所示:在向執行程序提交新任務時,如果我們已經在運行所有線程,並且已經在某個執行程序線程上運行,請以內聯方式運行任務。 這工作正常10個月,但現在我們遇到了問題。 如果提交的新任務仍然比較大,則可以進入新任務阻塞該方法的其他任務添加到隊列的情況,否則這些任務將被其他工作線程拾取。 所以當線程正在處理內聯工作時,你會遇到很大的延遲。

有沒有更好的解決方案來執行後台任務的潛在無限樹的核心問題? 我知道.NET的執行者服務相當於有一種內嵌的能力從隊列中竊取,防止了原來的死鎖問題的發生,據我所知,這是一個理想的解決方案。 但是在Java的土地呢?


似乎問題在於這些任務也試圖並行化,這使得很難避免資源限制。 你為什麼需要這樣做? 為什麼不總是內聯運行子任務?

如果你已經通過並行化來充分利用cpu,那麼就不需要把整個工作再分成更小的任務。





executorservice