在服务中实现线程池

cdr*_*oid 11 java multithreading android android-service

我正在努力实现一个Service,当被请求将在几个并行线程上执行一些工作.

我的实现基于ThreadPoolExecutor类和a LinkedBlockingQueue.

作为一项基本规则,一旦完成所有任务并且队列中没有待处理的任务,我想停止服务(尽管稍后可以再次启动服务并遵循相同的逻辑).

我已经能够使用下面的代码达到预期的结果,但我不确定这种方法是否正确.

public class TestService extends Service {
    // Sets the initial threadpool size to 3
    private static final int CORE_POOL_SIZE = 3;

    // Sets the maximum threadpool size to 3
    private static final int MAXIMUM_POOL_SIZE = 3;

    // Sets the amount of time an idle thread will wait for a task before terminating
    private static final int KEEP_ALIVE_TIME = 1;

    // Sets the Time Unit to seconds
    private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

    // A queue of Runnables for the uploading pool
    private final LinkedBlockingQueue<Runnable> uploadQueue = new LinkedBlockingQueue<Runnable>();

    // A managed pool of background upload threads
    private final ThreadPoolExecutor uploadThreadPool = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT,
            uploadQueue) {

        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);

            if (getActiveCount() == 1 && getQueue().size() == 0) {
                // we're the last Runnable around + queue is empty, service can be
                // safely stopped.
                TestService.this.stopSelf();
            }
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // execute a new Runnable
        uploadThreadPool.execute(new TestRunnable());

        /**
         * Indicating that if Android has to kill off this service (i.e. low memory),
         * it should not restart it once conditions improve.
         */
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        uploadThreadPool.shutdownNow();
        uploadQueue.clear();

        super.onDestroy();
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我有一些我还不确定的事情.

  1. 假设onDestroy被调用,是否可以安全地假设我的实现将中断所有正在运行的线程并安全地清除挂起的任务而不会以某种方式中断ThreadPoolExecutor类实现?我问的原因是因为队列与执行程序相关联,并且可能shutdownNow是异步的并且取决于队列的状态.有没有更好的方法呢?

  2. 我在内部正确实现这个逻辑onDestroy吗?根据我的经验,有些情况下服务被杀死(即内存不足),并且不会调用此回调.我是否应该在其他地方采用类似的方法?

  3. 将我的队列和执行程序类成员声明为静态会更好吗?- 正如@TheTwo所述"Excecutor cannot be re-used once shutdown is called".

  4. ThreadPoolExecutorclass期望a BlockingQueue,使用其他类型的BlockingQueue实现(即ArrayBlockingQueue)的优点/缺点是什么?

  5. 关于我当前检测队列是否为空并且没有更多待处理任务(特别是在afterExecute回调内)的方式 - 这是最好的方法吗?或者我可以得到队列为空并且任务以其他方式完成的指示吗?

感谢任何帮助!

Two*_*The 5

我认为你正在尝试实现一项服务,它引入了许多问题,但没有解决.实际上,您可以将调用代码减少一行 - 执行程序的创建 - 但是会删除对其进行精细控制的能力.调度许多任务没有任何好处,因为这已经由OS的线程调度程序解决了.此外,恶意调用者可以通过添加足够的while(true) sleep(100);循环来破坏其他几个程序.

关于你的问题:

  1. 您无法确保所有线程都被正确中断,因为无法中断未正确观察中断标志的线程.A while(true) ;除了之外不能被打断System.exit().理论上你可以停止一个线程,但是这个特性由于某种原因而被弃用,因为它可以使实际任务处于不完整/未完成状态(iE使TCP连接保持半开).

  2. 不,你没有正确实现它.对于一旦剩下的任务,队列就会在虚空中消失,然后一旦调用shutdown就不能重新使用Excecutor.所以你至少需要在服务启动时创建一个新的Excecutor实例,你真的应该弄清楚如何处理剩下的任务.

  3. 不,因为2.

  4. 列表类型的优缺点取决于您的用例.ArrayList在增长/收缩时成本较高,但在索引特定元素(indexOf)时成本较低,而链表则相反.由于你的队列总是添加到尾部,不关心任何其他元素而是第一个,并且它经常增长/缩小,链接列表是最佳选择.

  5. 您根本不应该以这种方式停止任务,因为未定义具有线程的执行顺序.在最坏的情况下,您的呼叫程序每次都会被中断,直到服务执行完毕,这将导致服务无缘无故地启动和停止,同时浪费了大量的处理时间.为什么你甚至想要停止服务?如果没有任何关系,除了使用几个字节的内存之外什么都不做.

  • 重新#5,关注http://www.youtube.com/watch?v=xHXn3Kg2IQE我的印象是,一旦服务完成它的工作,它应该停止,以保存电池并通知系统它可以释放资源,并且该服务已不再使用..是不是android决定根据这些信息销毁特定的运行组件? (2认同)