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