Java ExecutorService приостанавливает/возобновляет определенный поток

Есть ли способ использовать ExecutorService для приостановки/возобновления определенного потока?

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

Представьте, что я хочу остановить поток, как id = 0 (при условии, что каждому присваивается инкрементный идентификатор до тех пор, пока не будет достигнут размер потока).

Через некоторое время, нажав кнопку, скажем, я хочу возобновить этот конкретный поток и оставить все остальные потоки текущим статусом, который может быть приостановлен или возобновлен.

Я нашел в Java документации незавершенную версию PausableThreadPoolExecutor. Но это не подходит для того, что мне нужно, потому что оно возобновляет все потоки в пуле.

Если нет способа сделать это с реализацией по умолчанию ExecutorService, кто-нибудь может указать мне на реализацию Java для этой проблемы?

Спасибо!

Ответ 1

Вы ошиблись. Пул потоков владеет потоками, и, разделяя их с вашим кодом, может испортиться.
Вы должны сосредоточиться на выполнении своих задач (переданных в потоки, отменяемых/прерываемых) и не взаимодействовать с потоками, принадлежащими пулу напрямую.
Кроме того, вы не знаете, какая работа выполняется в то время, когда вы пытаетесь прервать поток, поэтому я не понимаю, почему вы были бы заинтересованы в этом.

Update:
Правильный способ отмены задачи, представленной в пуле потоков, - через Future для задачи, возвращенной исполнителем.
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();      
    }

Ответ 2

Предложение. Аналогично/вместо используемых флажков создайте semaphore с 1 разрешением (new Semaphore(1)) для каждая задача, которую вам нужно приостановить/приостановить. В начале рабочего цикла задачи введите такой код:

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

Это заставляет задачу получить разрешение на семафор и немедленно освободить ее. Теперь, если вы хотите приостановить поток (например, нажата кнопка), вызовите semaphore.acquire() из другого потока. Поскольку семафор имеет теперь 0 разрешений, ваш рабочий поток остановится в начале следующего цикла и дождитесь, пока вы вызовете semaphore.release() из другого потока.

(Метод acquire() выбрасывает InterruptedException, если ваш рабочий поток прерывается во время ожидания. Существует еще один метод acquireUninterruptibly(), который также пытается получить разрешение, но не прерывается.)