1package com.bumptech.glide.load.engine.executor;
2
3import java.util.concurrent.FutureTask;
4import java.util.concurrent.PriorityBlockingQueue;
5import java.util.concurrent.RunnableFuture;
6import java.util.concurrent.ThreadFactory;
7import java.util.concurrent.ThreadPoolExecutor;
8import java.util.concurrent.TimeUnit;
9import 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 */
17public 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     */
26    public FifoPriorityThreadPoolExecutor(int poolSize) {
27        this(poolSize, poolSize, 0, TimeUnit.MILLISECONDS, new DefaultThreadFactory());
28    }
29
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
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
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
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
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
86        public int hashCode() {
87            int result = priority;
88            result = 31 * result + order;
89            return result;
90        }
91
92        @Override
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