summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/PriorityTaskQueue.java
blob: bbd49101f432508a615281d7b8299a0b338f6671 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * 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 <code>PriorityTask</code>.
 */
public class PriorityTaskQueue {

    private ThreadPoolExecutor mExecutor;

    /*private*/ boolean mShutdown = false;
    /*private*/ IdentityHashMap<PriorityTask<?>, Object> mActiveTasks =
            new IdentityHashMap<PriorityTask<?>, 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<Runnable>());
    }

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

    <T> void removeCanceledTask(PriorityTask<T> 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<PriorityTaskQueue> mQueueRef;

        public LocalExecutor(PriorityTaskQueue queue,
                int corePoolSize, int maximumPoolSize, long keepAliveTime,
                TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                    workQueue);
            mQueueRef = new WeakReference<PriorityTaskQueue>(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);
                }
            }
        }
    }

}