10

有没有办法使用 ExecutorService 来暂停/恢复特定线程?

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

想象一下,我想停止 id=0 的线程(假设为每个线程分配一个增量 id,直到达到线程池的大小)。

过了一会儿,假设按下一个按钮,我想恢复该特定线程,并使所有其他线程保持当前状态,可以暂停或恢复。

我在 Java 文档中发现了一个未完成的 PausableThreadPoolExecutor 版本。但它不适合我的需要,因为它恢复了池中的所有线程。

如果没有办法使用 ExecutorService 的默认实现来做到这一点,任何人都可以为我指出这个问题的 Java 实现吗?

4

3 回答 3

8

你走错了路。线程池拥有线程,并且通过与您的代码共享它们可能会使事情变得混乱。
您应该专注于使您的任务(传递给线程可取消/可中断),而不是直接与池拥有的线程交互。
此外,当您尝试中断线程时,您不会知道正在执行什么作业,所以我不明白您为什么会对这样做感兴趣

更新:
取消在线程池中提交的任务的正确方法是通过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();      
    }
于 2012-08-11T15:38:28.820 回答
4

建议:与您正在使用的标志类似/代替您使用的标志,为您需要暂停/取消暂停的每个任务创建一个带有 1 个许可 ( ) 的信号量。new Semaphore(1)在任务的工作周期的开始放一个这样的代码:

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

这会导致任务获取信号量许可并立即释放它。现在,如果您想暂停线程(例如按下按钮),请semaphore.acquire()从另一个线程调用。由于信号量现在有 0 个许可,您的工作线程将在下一个周期开始时暂停,并等待您semaphore.release()从另一个线程调用。

(如果您的工作线程在等待时被中断,该acquire()方法会抛出InterruptedException。还有另一种方法acquireUninterruptibly(),它也尝试获取许可,但不会被中断。)

于 2012-08-11T18:52:48.610 回答
-1

一种情况可能是,一个人想要模拟许多设备。设备具有功能。总的来说,这组设备同时运行。现在,如果一个线程代表一个设备(或一个线程代表设备的一项功能),则可能想要控制设备的生命周期,例如start(), shutdown(), resume()

于 2020-02-11T13:46:23.487 回答