1a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert/*
2a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * Copyright (C) 2009 The Android Open Source Project
3a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert *
4a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
5a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * you may not use this file except in compliance with the License.
6a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * You may obtain a copy of the License at
7a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert *
8a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert *      http://www.apache.org/licenses/LICENSE-2.0
9a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert *
10a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * Unless required by applicable law or agreed to in writing, software
11a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
12a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * See the License for the specific language governing permissions and
14a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * limitations under the License.
15a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert */
16a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
17a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertpackage com.android.quicksearchbox.util;
18a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
19a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport android.util.Log;
20a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
21a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport java.util.concurrent.LinkedBlockingQueue;
22a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport java.util.concurrent.ThreadFactory;
23a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
24a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert/**
25a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert * Executor that uses a single thread and an unbounded work queue.
26a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert */
27a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertpublic class SingleThreadNamedTaskExecutor implements NamedTaskExecutor {
28a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
29b5fc08b7f16a32d3865f44b7f26d8aaa5304a2adBjorn Bringert    private static final boolean DBG = false;
30a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private static final String TAG = "QSB.SingleThreadNamedTaskExecutor";
31a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
32a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private final LinkedBlockingQueue<NamedTask> mQueue;
33a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private final Thread mWorker;
34a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private volatile boolean mClosed = false;
35a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
36a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    public SingleThreadNamedTaskExecutor(ThreadFactory threadFactory) {
37a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        mQueue = new LinkedBlockingQueue<NamedTask>();
38a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        mWorker = threadFactory.newThread(new Worker());
39a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        mWorker.start();
40a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    }
41a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
42a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    public void cancelPendingTasks() {
4347d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert        if (DBG) Log.d(TAG, "Cancelling " + mQueue.size() + " tasks: " + mWorker.getName());
44a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        if (mClosed) {
45a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert            throw new IllegalStateException("cancelPendingTasks() after close()");
46a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        }
47a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        mQueue.clear();
48a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    }
49a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
50a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    public void close() {
51a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        mClosed = true;
52a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        mWorker.interrupt();
53a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        mQueue.clear();
54a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    }
55a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
56a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    public void execute(NamedTask task) {
57a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        if (mClosed) {
58a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert            throw new IllegalStateException("execute() after close()");
59a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        }
60a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        mQueue.add(task);
61a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    }
62a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
63a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private class Worker implements Runnable {
64a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        public void run() {
65c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney            try {
66c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney                loop();
67c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney            } finally {
68c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney                if (!mClosed) Log.w(TAG, "Worker exited before close");
69c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney            }
70c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney        }
71c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney
72c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney        private void loop() {
73c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney            Thread currentThread = Thread.currentThread();
74c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney            String threadName = currentThread.getName();
75a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert            while (!mClosed) {
76a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                NamedTask task;
77a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                try {
78a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                    task = mQueue.take();
79a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                } catch (InterruptedException ex) {
80c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney                    continue;
81a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                }
82c963d16e55b6dc2bf37526455ff2c05150b2bfa2Bryan Mawhinney                currentThread.setName(threadName + " " + task.getName());
83a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                try {
844572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood                    if (DBG) Log.d(TAG, "Running task " + task.getName());
85a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                    task.run();
864572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood                    if (DBG) Log.d(TAG, "Task " + task.getName() + " complete");
87a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                } catch (RuntimeException ex) {
88a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                    Log.e(TAG, "Task " + task.getName() + " failed", ex);
89a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                }
90a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert            }
91a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        }
92a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    }
93a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
94a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    public static Factory<NamedTaskExecutor> factory(final ThreadFactory threadFactory) {
95a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        return new Factory<NamedTaskExecutor>() {
96a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert            public NamedTaskExecutor create() {
97a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert                return new SingleThreadNamedTaskExecutor(threadFactory);
98a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert            }
99a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        };
100a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    }
101a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
102a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert}
103