10

ExecutorService を使用して特定のスレッドを一時停止/再開する方法はありますか?

private static ExecutorService threadpool = Executors.newFixedThreadPool(5);

id=0 のスレッドを停止したいとします (スレッドプールのサイズに達するまで、それぞれに増分 ID が割り当てられていると仮定します)。

しばらくすると、ボタンを押して、その特定のスレッドを再開し、他のすべてのスレッドを現在のステータスのままにして、一時停止または再開したいとします。

Java ドキュメントで PausableThreadPoolExecutor の未完成バージョンを見つけました。しかし、プール内のすべてのスレッドを再開するため、必要なものには合いません。

ExecutorService のデフォルトの実装でそれを行う方法がない場合、誰かがこの問題の Java 実装を指摘できますか?

4

3 に答える 3

8

あなたは間違った道を進んでいます。スレッド プールはスレッドを所有しており、それらをコードと共有すると、問題が発生する可能性があります。タスク (スレッドにキャンセル可能/割り込み可能に渡す) を作成する
ことに集中し、プールが所有するスレッドと直接対話しないようにする必要があります。 さらに、スレッドを中断しようとした時点で実行されているジョブがわからないため、なぜこれを行うことに関心があるのか​​ わかりません

更新:
スレッド プールに送信されたタスクをキャンセルする適切な方法はFuture、executor によって返されたタスクを使用することです。
1) こうすることで、実際に狙っているタスクがキャンセルされようとしていることが確実にわかる
2) タスクがすでにキャンセル可能になるように設計されている場合は、途中である
3) キャンセルを示すフラグを使用せず、Thread.currentThread().interrupt()代わりに フラグを使用する

アップデート:

public class InterruptableTasks {  

    private static class InterruptableTask implements Runnable{  
        Object o = new Object();  
        private volatile boolean suspended = false;  

        public void suspend(){          
            suspended = true;  
        }  

        public void resume(){       
            suspended = false;  
            synchronized (o) {  
                o.notifyAll();  
            }  
        }  


        @Override  
        public void run() {  

            while(!Thread.currentThread().isInterrupted()){  
                if(!suspended){  
                    //Do work here      
                }
                else{  
                    //Has been suspended  
                    try {                   
                        while(suspended){  
                            synchronized(o){  
                                o.wait();  
                            }                           
                        }                       
                    }  
                    catch (InterruptedException e) {                    
                    }             
                }                           
            }  
            System.out.println("Cancelled");        
        }

    }

    /**  
     * @param args  
     * @throws InterruptedException   
     */  
    public static void main(String[] args) throws InterruptedException {  
        ExecutorService threadPool = Executors.newCachedThreadPool();  
        InterruptableTask task = new InterruptableTask();  
        Map<Integer, InterruptableTask> tasks = new HashMap<Integer, InterruptableTask>();  
        tasks.put(1, task);  
        //add the tasks and their ids

        Future<?> f = threadPool.submit(task);  
        TimeUnit.SECONDS.sleep(2);  
        InterruptableTask theTask = tasks.get(1);//get task by id
        theTask.suspend();  
        TimeUnit.SECONDS.sleep(2);  
        theTask.resume();  
        TimeUnit.SECONDS.sleep(4);                
        threadPool.shutdownNow();      
    }
于 2012-08-11T15:38:28.820 に答える
4

提案: 使用しているフラグと同様に/その代わりに、一時停止/一時停止解除する必要があるタスクごとに 1 つの permit ( ) を持つセマフォを作成します。new Semaphore(1)タスクの作業サイクルの開始時に、次のようなコードを配置します。

semaphore.acquire();
semaphore.release();

これにより、タスクはセマフォ許可を取得し、すぐに解放します。スレッドを一時停止したい場合 (たとえば、ボタンが押された場合) は、semaphore.acquire()別のスレッドから呼び出します。セマフォのパーミットが 0 になったので、作業中のスレッドは次のサイクルの開始時に一時停止しsemaphore.release()、他のスレッドから呼び出すまで待機します。

(待機中に作業スレッドが中断された場合、acquire()メソッドは をスローします。別のメソッドもあり、これも許可を取得しようとしますが、中断されません。)InterruptedExceptionacquireUninterruptibly()

于 2012-08-11T18:52:48.610 に答える