1 package com.bumptech.glide.load.engine.executor; 2 3 import java.util.concurrent.FutureTask; 4 import java.util.concurrent.PriorityBlockingQueue; 5 import java.util.concurrent.RunnableFuture; 6 import java.util.concurrent.ThreadFactory; 7 import java.util.concurrent.ThreadPoolExecutor; 8 import java.util.concurrent.TimeUnit; 9 import java.util.concurrent.atomic.AtomicInteger; 10 11 /** 12 * A FIFO priority {@link ThreadPoolExecutor} that prioritizes submitted {@link Runnable}s by assuming they implement 13 * {@link Prioritized}. {@link Prioritized} runnables that return lower values for {@link Prioritized#getPriority()} 14 * will be executed before those that return higher values. Priorities only apply when multiple items are queued at the 15 * same time. Runnables with the same priority will be executed in FIFO order. 16 */ 17 public class FifoPriorityThreadPoolExecutor extends ThreadPoolExecutor { 18 AtomicInteger ordering = new AtomicInteger(); 19 20 /** 21 * Constructor to build a fixed thread pool with the given pool size using 22 * {@link com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor.DefaultThreadFactory}. 23 * 24 * @param poolSize The number of threads. 25 */ FifoPriorityThreadPoolExecutor(int poolSize)26 public FifoPriorityThreadPoolExecutor(int poolSize) { 27 this(poolSize, poolSize, 0, TimeUnit.MILLISECONDS, new DefaultThreadFactory()); 28 } 29 FifoPriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAlive, TimeUnit timeUnit, ThreadFactory threadFactory)30 public FifoPriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAlive, TimeUnit timeUnit, 31 ThreadFactory threadFactory) { 32 super(corePoolSize, maximumPoolSize, keepAlive, timeUnit, new PriorityBlockingQueue<Runnable>(), threadFactory); 33 } 34 35 @Override newTaskFor(Runnable runnable, T value)36 protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { 37 return new LoadTask<T>(runnable, value, ordering.getAndIncrement()); 38 } 39 40 /** 41 * A {@link java.util.concurrent.ThreadFactory} that builds threads with priority 42 * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}. 43 */ 44 public static class DefaultThreadFactory implements ThreadFactory { 45 int threadNum = 0; 46 @Override newThread(Runnable runnable)47 public Thread newThread(Runnable runnable) { 48 final Thread result = new Thread(runnable, "fifo-pool-thread-" + threadNum) { 49 @Override 50 public void run() { 51 android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); 52 super.run(); 53 } 54 }; 55 threadNum++; 56 return result; 57 } 58 } 59 60 // Visible for testing. 61 static class LoadTask<T> extends FutureTask<T> implements Comparable<LoadTask<?>> { 62 private final int priority; 63 private final int order; 64 LoadTask(Runnable runnable, T result, int order)65 public LoadTask(Runnable runnable, T result, int order) { 66 super(runnable, result); 67 if (!(runnable instanceof Prioritized)) { 68 throw new IllegalArgumentException("FifoPriorityThreadPoolExecutor must be given Runnables that " 69 + "implement Prioritized"); 70 } 71 priority = ((Prioritized) runnable).getPriority(); 72 this.order = order; 73 } 74 75 @SuppressWarnings("unchecked") 76 @Override equals(Object o)77 public boolean equals(Object o) { 78 if (o instanceof LoadTask) { 79 LoadTask<Object> other = (LoadTask<Object>) o; 80 return order == other.order && priority == other.priority; 81 } 82 return false; 83 } 84 85 @Override hashCode()86 public int hashCode() { 87 int result = priority; 88 result = 31 * result + order; 89 return result; 90 } 91 92 @Override compareTo(LoadTask<?> loadTask)93 public int compareTo(LoadTask<?> loadTask) { 94 int result = priority - loadTask.priority; 95 if (result == 0) { 96 result = order - loadTask.order; 97 } 98 return result; 99 } 100 } 101 } 102