В настоящее время я работаю над реализацией Service
, который по запросу будет выполнять некоторую работу над несколькими параллельными потоками.
Моя реализация основана на классе ThreadPoolExecutor
наряду с 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();
}
}
Итак, у меня есть кое-что, о чем я еще не уверен.
-
Предполагалось, что
onDestroy
был вызван, можно ли предположить, что моя реализация прервет ВСЕ выполняемые потоки и будет безопасно очищать ожидающие задачи без какого-либо прерывания с помощью реализации классаThreadPoolExecutor
? причина, по которой я спрашиваю, связана с тем, что очередь связана с исполнителем, и, возможно,shutdownNow
является асинхронной и зависит от состояния очереди. Есть ли лучший способ сделать это? -
Правильно ли я реализую эту логику внутри
onDestroy
? из моего опыта есть некоторые случаи, когда служба убита (т.е. низкая память), и этот обратный вызов не вызывается. Должен ли я выполнять аналогичный подход и в других местах? -
Было бы лучше объявить члены класса очереди и исполнителя как статические?- Как указано в @TheTwo"Excecutor cannot be re-used once shutdown is called"
. -
ThreadPoolExecutor
класс ожидаетBlockingQueue
, каковы плюсы и минусы использования других типов реализацийBlockingQueue
(т.е.ArrayBlockingQueue
)? -
Относительно того, как я в настоящее время обнаруживаю, когда очередь пуста, и больше нет ожидающих задач (в частности, внутри
afterExecute
) - это лучший способ сделать это? Или я могу получить указание, что очередь пуста, а задачи закончены по-другому?
Цените любую помощь!