/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.camera; import java.lang.ref.WeakReference; import java.util.IdentityHashMap; import java.util.concurrent.BlockingQueue; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * The thread queue for PriorityTask. */ public class PriorityTaskQueue { private ThreadPoolExecutor mExecutor; /*private*/ boolean mShutdown = false; /*private*/ IdentityHashMap, Object> mActiveTasks = new IdentityHashMap, Object>(); /** * Creates a queue with fixed pool size. */ public PriorityTaskQueue(int size) { this(size, size, 0); } /** * Creates a queue with dynamic pool size. * * @param coreSize the minimum size of the thread pool * @param maxSize the maximum size of the thread pool * @param keepAlive the keep alive time for idle thread (in milliseconds) */ public PriorityTaskQueue(int coreSize, int maxSize, long keepAlive) { mExecutor = new LocalExecutor( this, coreSize, maxSize, keepAlive, TimeUnit.MILLISECONDS, new PriorityBlockingQueue()); } public boolean add(PriorityTask task) { synchronized (task) { if (task.setupBeforeQueued(this)) { synchronized (mActiveTasks) { if (mShutdown) throw new IllegalStateException(); mActiveTasks.put(task, null); } mExecutor.execute(task); return true; } return false; } } public boolean remove(PriorityTask task) { synchronized (task) { if (mExecutor.remove(task)) { synchronized (mActiveTasks) { if (!mShutdown) mActiveTasks.remove(task); } task.resetState(); return true; } return false; } } /** * Shutdowns the task queue gracefully. The tasks added into the queue will * be executed, but no more tasks are allowed to enter the queue. */ public void shutdown() { mShutdown = true; mExecutor.shutdown(); } /** * Shutdowns the task queue immediately. All the tasks in the queue will be * requested to cancel. If some tasks ignore the cancel request, it may * blocked until those tasks are finished. */ public void shutdownNow() { synchronized (mActiveTasks) { mShutdown = true; for (PriorityTask task : mActiveTasks.keySet()) { task.requestCancel(); } } mExecutor.shutdown(); } void removeCanceledTask(PriorityTask t) { synchronized (mActiveTasks) { if (!mShutdown) mActiveTasks.remove(t); } mExecutor.remove(t); } @Override protected void finalize() { if (!mShutdown) shutdown(); } private static class LocalExecutor extends ThreadPoolExecutor { // Uses weak reference so that PriorityTaskQueue can be finalized // when no others use it and than close this thread pool. private WeakReference mQueueRef; public LocalExecutor(PriorityTaskQueue queue, int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); mQueueRef = new WeakReference(queue); } @Override public void afterExecute(Runnable r, Throwable t) { PriorityTaskQueue queue = mQueueRef.get(); if (queue != null) { synchronized (queue.mActiveTasks) { if (!queue.mShutdown) queue.mActiveTasks.remove(r); } } } } }