Java ExecutorService - 任务/可调用不取消/中断

时间:2017-07-29 14:03:37

标签: java android multithreading threadpool executorservice

我使用Java ExecutorService(ThreadPool)来执行任务&在特定活动处于前台(可见)时更新UI。

问题: 我想要的是当用户切换到另一个活动我想要停止/取消所有任务(无论是排队还是正在运行)。为此,我必须在通过调用isDone()检查Future对象状态后,对ExecutorService提交方法返回的Future对象使用ExecutorService shutdown / shutdownNow方法或cancel(true)。这会将中断的相应线程标志设置为TRUE,我必须在我的可调用实现中检查(Thread.currentThread.isInterrupted())以确定是否中断退出任务/线程。问题是我是否在两种情况下都调用了ExecutorService shutdown方法或Future cancel(true)方法,它很少将10次设置线程中断标志为TRUE,最终导致内存泄漏等等。

代码:

ThreadPool Singleton实现(cancelAll-取消任务& shutdownExecutor-关闭ExecutorService):

private static class ThreadPoolManager {

    private ExecutorService executorService;
    private List<Future> queuedFutures;
    private BlockingQueue<Runnable> blockingQueue;

    private static ThreadPoolManager instance;

    private ThreadPoolManager() {
        MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Threadpool-created(constructor)");
        queuedFutures = new ArrayList<>();
        blockingQueue = new LinkedBlockingDeque<>();
        executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(), 1, TimeUnit.SECONDS, blockingQueue);
    }

    static {
        instance = new ThreadPoolManager();
    }

    public static void submitItemTest(Callable<Object> callable) {
        MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Threadpool-submitted item test");
        if(instance.executorService.isShutdown()){
            instance=new ThreadPoolManager();
        }
        Future future = instance.executorService.submit(callable);
        instance.queuedFutures.add(future);
    }

    public static void submitTestAll(Callable<Object> callable) {
        MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Threadpool-submitted test all");
        if(instance.executorService.isShutdown()){
            instance=new ThreadPoolManager();
        }
        cancelAll();
        Future future = instance.executorService.submit(callable);
        instance.queuedFutures.add(future);
    }

    public static void cancelAll() {
        MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Cancelling all future tasks");
        instance.blockingQueue.clear();
        for (Future future : instance.queuedFutures) {
            if (!future.isDone()) {
                boolean cancelled = future.cancel(true);
                MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Cancelled-" + cancelled);
            }
        }
        instance.queuedFutures.clear();
    }

    public static void shutdownExecutor(){
        MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Shuttingdown threadpool");
        instance.executorService.shutdownNow();
    }
}

可调用实现(正常迭代和检查中断的if子句):

private Callable<Object> getTestAllCallable() {
        return new Callable<Object>() {
            @Override
            public Object call() {
                for (int i = 0; i < inbuiltProxyPojoArrayList.size(); i++) {
                    if (!Thread.currentThread().isInterrupted()) {
                          //someWork

                    } else {
                        MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "ThreadInterrupted-Cancelling");
                        return null;
                    }
                }
                return null;
            }
        };
    }

活动/片段onStop实现(用于调用取消任务和关闭):

@Override
public void onStop() {
    MyLogger.log(MyLogger.LOG_TYPE.INFO, "onStop called");
    ThreadPoolManager.cancelAll();
    ThreadPoolManager.shutdownExecutor();
    super.onStop();
}

更新

所做的更改:

  1. 使用Runnable而不是callable。

  2. 现在不使用单例执行ExecutorService。

      private class ThreadPoolManager {
    
        private ExecutorService executorService;
        private List<Future> queuedFutures;
        private BlockingQueue<Runnable> blockingQueue;
    
        private ThreadPoolManager() {
            MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Threadpool-created(constructor)");
            queuedFutures = new ArrayList<>();
            blockingQueue = new LinkedBlockingDeque<>();
            executorService =getNewExecutorService();
        }
    
        private ExecutorService getNewExecutorService(){
            return new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(), 1, TimeUnit.SECONDS, blockingQueue);
        }
    
        private void submitItemTest(Runnable runnable) {
            MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Threadpool-submitted item test");
            if(executorService.isShutdown()){
                executorService=getNewExecutorService();
            }
            Future future = executorService.submit(runnable);
            queuedFutures.add(future);
        }
    
        private void submitTestAll(Runnable runnable) {
            MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Threadpool-submitted test all");
            if(executorService.isShutdown()){
                executorService=getNewExecutorService();
            }
            cancelAll();
            Future future = executorService.submit(runnable);
            queuedFutures.add(future);
        }
    
        private void cancelAll() {
            MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Cancelling all future tasks");
            blockingQueue.clear();
            for (Future future : queuedFutures) {
                if (!future.isDone()) {
                    boolean cancelled = future.cancel(true);
                    MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Cancelled-" + cancelled);
                }
            }
            queuedFutures.clear();
        }
    
        private void shutdownExecutor(){
            MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Shuttingdown threadpool");
            executorService.shutdownNow();
            blockingQueue.clear();
            queuedFutures.clear();
        }
    }
    
  3. 找出了罪魁祸首,但尚未找到解决方案。以下2是Runnables 1的实现正在运行(isInterrupted返回true或来自InterupptedException而不是任务结束)但不是其他。

    Working Runnable(我用它进行测试):

    new Runnable() {
              @Override
              public void run() {
                        int i=0;
                        while(!Thread.currentThread().isInterrupted()){
                            try {
                                System.out.println(i);
                                Thread.currentThread().sleep(2000);
                            } catch (InterruptedException e) {
                                MyLogger.log(MyLogger.LOG_TYPE.DEBUG,"Interrupted");
                                return;
                            }
                            i++;
                        }
                    }
                }
    

    不工作(我想使用的实际代码):

    new Runnable(){
                @Override
                public void run() {
                    for (int i = 0; i < inbuiltProxyPojoArrayList.size(); i++) {
                        if (!Thread.currentThread().isInterrupted()) {
    
                        } else {
                            MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "Thread Interrupted (Cancelled)");
                            break;
                        }
                    }
                }
            };
    

    一个可能的解决方案是使用变量(布尔值)作为runnable中的中断标志,我将其视为最后的手段,但很乐意了解错误。

2 个答案:

答案 0 :(得分:0)

根据ExecutorService文档,关闭执行任务是在尽力而为的基础上完成的。

因此,当您致电ExecutorService.shutdownNow()时,实施将尝试关闭所有当前正在执行的任务。每个任务都会一直运行,直到它到达检测到它被中断的程度。

为了确保你的线程在早期阶段达到这一点,最好在你的循环中添加一个检查线程是否被中断,如下所示:

Thread.currentThread().isInterrupted();

通过在每次迭代时进行此调用,您的线程将检测到与实际交互的间隔很短的中断。

因此,您修改后的Callable代码将如下所示:

private Callable<Object> getTestAllCallable() {
    return new Callable<Object>() {
        @Override
        public Object call() {
            for (int i = 0; i < inbuiltProxyPojoArrayList.size(); i++) {
                if(Thread.currentThread().isInterrupted()) {
                    return null;
                }
                if(someCondition) {
                    //someWork
                } else {
                    MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "ThreadInterrupted-Cancelling");
                    return null;
                }
            }
            return null;
        }
    };
}

顺便说一句,如果您不打算从Callable方法返回任何值,则使用call()没有意义。如果您在任务中需要参数化类型,只需创建参数化Runnable,如下所示:

public class ParameterizedRunnable<T> implements Runnable {
    private final T t;

    public ParameterizedRunnable(T t) {
        this.t = t;
    }

    public void run() {
        //do some work here
    }
}

答案 1 :(得分:0)

解决方案(出路): 所以最后我继续使用自定义内部标志(布尔值)作为线程中断标志,每次迭代都会通过MyRunnable检查(使用自定义标志自定义实现runnable,以便有一个与每个runnable相关联的标志)。比当需要在ExecutorService(ThreadPool)下取消线程时,我遍历所有Future对象并将其与MyRunnable相关联,然后将其中断标志(自定义标志)设置为true,而不是中断/关闭线程。

<强> ThreadPoolManager:

private class ThreadPoolManager {

        private ExecutorService executorService;
        private final Map<Future,MyRunnable> queuedFutures;
        private final BlockingQueue<Runnable> blockingQueue;

        private ThreadPoolManager() {
            MyLogger.log(DEBUG, "Threadpool-created(constructor)");
            queuedFutures = new HashMap<>();
            blockingQueue = new LinkedBlockingDeque<>();
            executorService = getNewExecutorService();
        }

        private ExecutorService getNewExecutorService() {
            return new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(), 1, TimeUnit.SECONDS, blockingQueue);
        }

        private void submitItemTest(MyRunnable runnable) {
            MyLogger.log(DEBUG, "Threadpool-submitted item test");
            if (executorService.isShutdown()) {
                executorService = getNewExecutorService();
            }
            Future future = executorService.submit(runnable);
            queuedFutures.put(future,runnable);
        }

        private void submitTestAll(MyRunnable runnable) {
            MyLogger.log(DEBUG, "Threadpool-submitted test all");
            if (executorService.isShutdown()) {
                executorService = getNewExecutorService();
            }
            cancelAll();
            Future future = executorService.submit(runnable);
            queuedFutures.put(future,runnable);
        }

        private void cancelAll() {
            MyLogger.log(DEBUG, "ThreadPool: Cancelling all future tasks");
            blockingQueue.clear();
            for (Future future : queuedFutures.keySet()) {
                if (!future.isDone()) {
                    queuedFutures.get(future).continueRunning=false;
                    MyLogger.log(DEBUG, "Cancelled");
                }
            }
            queuedFutures.clear();
        }

        private void shutdownExecutor() {
            cancelAll();
            MyLogger.log(DEBUG, "ThreadPool: Shuttingdown threadpool");
            executorService.shutdown();
        }
    }

MyRunnable(实现Runable的抽象类):

private abstract class MyRunnable implements Runnable {
        boolean continueRunning=true;
    }

MyRunnable(抽象类MyRunnable的实例):

new MyRunnable() {
       @Override
       public void run() {
           for (int i = 0; i < inbuiltProxyPojoArrayList.size(); i++) {
                 if (continueRunning) {
                        //someWork
                 } else {
                    MyLogger.log(MyLogger.LOG_TYPE.DEBUG, "ThreadPool: Pool Thread Interrupted (closing down)");
                     break;
                 }
            }
            System.out.println("ThreadPool: Test complete");
         }
     };

现在,调用threadPoolManager.shutdownExecutor()关闭/中断当前正在运行的所有线程。