11

初めて先物を使おうとしています。ジョブをキャンセルできるのは賢いようですが、期待どおりに機能していません。以下の例では、最初のジョブのみがキャンセルされます。残りは完了です。先物の使い方を誤解していませんか?

public class ThreadExample 
{
    public static void main(String[] args) throws InterruptedException, ExecutionException 
    {
        int processors = Runtime.getRuntime().availableProcessors();
        System.out.println("Processors: " + processors);
        ExecutorService es = Executors.newFixedThreadPool(processors);
        int nowork = 10;
        Future<Integer>[] workres = new Future[nowork];
        for(int i = 0; i < nowork; i++)
        {
            workres[i] = es.submit(new SomeWork(i));
        }
        for(int i = 0; i < nowork; i++) 
        {
            if(i % 2 == 0)
            {
                System.out.println("Cancel");
                workres[i].cancel(true);
            }
            if(workres[i].isCancelled())
            {
                System.out.println(workres[i] + " is cancelled");
            }
            else
            {
                System.out.println(workres[i].get());
            }
        }
        es.shutdown();
    }
}

class SomeWork implements Callable<Integer> 
{
    private int v;
    public SomeWork(int v) 
    {
        this.v = v;
    }

    @Override
    public Integer call() throws Exception
    {
        TimeUnit.SECONDS.sleep(5);
        System.out.println(v + " done at " + (new Date()));
        return v;
    }
}

出力:

Processors: 4
Cancel
java.util.concurrent.FutureTask@10d448 is cancelled
4 done at Wed May 12 17:47:05 CEST 2010
2 done at Wed May 12 17:47:05 CEST 2010
1 done at Wed May 12 17:47:05 CEST 2010
3 done at Wed May 12 17:47:05 CEST 2010
1
Cancel
2  
3
Cancel
4
5 done at Wed May 12 17:47:10 CEST 2010
7 done at Wed May 12 17:47:10 CEST 2010
8 done at Wed May 12 17:47:10 CEST 2010
6 done at Wed May 12 17:47:10 CEST 2010  
5
Cancel
6
7
Cancel
8
9 done at Wed May 12 17:47:15 CEST 2010  
9
4

2 に答える 2

8

は、すでに実行中のジョブをFuture#cancel()終了/中断しません。まだ実行されていないジョブのみがキャンセルされます。

更新:polygenelubricantsが根本原因を突き止めました(+1):改善されたコードは次のとおりです:

int processors = Runtime.getRuntime().availableProcessors();
System.out.println("Processors: " + processors);
ExecutorService es = Executors.newFixedThreadPool(processors);
int nowork = 10;
Future<Integer>[] workers = new Future[nowork];

for (int i = 0; i < nowork; i++) {
    final int ii = i;
    workers[i] = es.submit(new Callable<Integer>() {
        public Integer call() throws Exception {
            return ii;
        }
    });
}

for (int i = 0; i < nowork; i++) {
    if (i % 2 == 0) {
        System.out.println("Cancel worker " + i);
        workers[i].cancel(true);
    }
}

for (int i = 0; i < nowork; i++) {
    if (workers[i].isCancelled()) {
        System.out.println("Worker " + i + " is cancelled");
    } else {
        System.out.println("Worker " + i + " returned: " + workers[i].get());
    }
}

es.shutdown();

結果:

プロセッサー:2
ワーカー0をキャンセル
ワーカー2をキャンセル
ワーカー4をキャンセル
ワーカー6をキャンセル
ワーカー8をキャンセル
ワーカー0はキャンセルされました
労働者1が戻った:1
ワーカー2はキャンセルされました
労働者3が戻った:3
ワーカー4はキャンセルされました
労働者5が戻った:5
ワーカー6はキャンセルされました
労働者7が戻った:7
ワーカー8はキャンセルされました
労働者9が戻った:9

workers(ではなく、であることに注意してくださいworkres)。

于 2010-05-12T16:11:54.213 に答える
8

問題は、キャンセルループがget()ブロックするループとオーバーラップしていることです。2つのループが欲しいと思いますよね?偶数のジョブをキャンセルする1つのループと、キャンセルされたジョブとキャンセルされていないジョブをチェックする2番目のループ、そしてそれget()に応じて。

現在の記述方法では、ループがキャンセルされる前に、workres[2]チェックしてget()から要求しましたworkres[1]

したがって、3つのフェーズが必要だと思います。

1. The `submit()` loop
2. The selective `cancel()` loop
3. The selective `get()` loop (which blocks)
于 2010-05-12T16:13:47.903 に答える