Java ExecutorService 暂停/恢复特定线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11915968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 06:55:25  来源:igfitidea点击:

Java ExecutorService pause/resume a specific thread

javamultithreadingconcurrencythreadpoolexecutorservice

提问by Ricardo Santos

Is there a way to use ExecutorService to pause/resume a specific thread?

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

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

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

Imagine that I want to stop the thread wich as the id=0 (assuming that to each one is assigned an incremental id until the size of the threadpool is reached).

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

After a while, by pressing a button let's say, I want to resume that specific thread and leave all the other threads with their current status, which can be paused or resumed.

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

I have found on Java documentation a uncompleted version of PausableThreadPoolExecutor. But it doesn't suit what I need because it resume all the threads in the pool.

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

If there's no way to do it with the default implementation of the ExecutorService can anyone point me to a Java implementation for this problem?

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

Thanks!

谢谢!

采纳答案by Cratylus

You are on the wrong track. The thread pool owns the threads and by sharing them with your code could mess things up.
You should focus on making your tasks(passed to the threads cancellable/interruptable) and not interact with the threads owned by the pool directly.
Additionally you would not know what job is being executed at the time you try to interrupt the thread, so I can't see why you would be interested in doing this

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

Update:
The proper way to cancel your task submitted in the thread pool is via the Futurefor the task returned by the executor.
1)This way you know for sure that the task you actually aim at is attempted to be cancelled
2)If your tasks are already designed to be cancellable then your are half way there
3) Do not use a flag to indicate cancellation but use Thread.currentThread().interrupt()instead

更新:
取消在线程池中提交的任务的正确方法是通过Future执行程序返回的任务。
1)你肯定知道你真正的目的是试图任务被取消这样
2)如果你的任务已经被设计为撤销那么你有一半的方式有
3)不要使用标志来表明取消,但使用Thread.currentThread().interrupt()替代

Update:

更新:

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();      
    }

回答by Petr Pudlák

Suggestion: Similarly to/instead of the flags you're using, create a semaphorewith 1 permit (new Semaphore(1)) for each task you need to pause/unpause. At the beginning of the task's working cycle put a code like this:

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

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

This causes the task to acquire a semaphore permit and immediately release it. Now if you want to pause the thread (a button is pressed, for example), call semaphore.acquire()from another thread. Since the semaphore has 0 permits now, your working thread will pause at the beginning of the next cycle and wait until you call semaphore.release()from the other thread.

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

(The acquire()method throws InterruptedException, if your working thread gets interrupted while waiting. There is another method acquireUninterruptibly(), which also tries to acquire a permit, but doesn't get interrupted.)

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

回答by springified

One scenario could be, one wants to simulate a number of devices. Devices have functions. Altogether this collection of devices runs concurrently. And now if a thread represents a device ( or one thread for one function of a device ), one might want to control the life cycle of the device like start(), shutdown(), resume()

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