我使用ExecutorService为我的应用程序编写了一个懒惰的图像下载程序。它使我能够很好地控制在什么时间并行运行多少下载等。使用LIFO订购的执行服务
现在,我唯一的问题是,如果我提交任务,它会在队列尾部(FIFO)结束。
有谁知道如何将此更改为LIFO?
我使用ExecutorService为我的应用程序编写了一个懒惰的图像下载程序。它使我能够很好地控制在什么时间并行运行多少下载等。使用LIFO订购的执行服务
现在,我唯一的问题是,如果我提交任务,它会在队列尾部(FIFO)结束。
有谁知道如何将此更改为LIFO?
您需要指定ExecutorService正在使用的队列类型。
通常,您可能正在通过Executors中的静态方法检索ExecutorService。相反,您需要直接实例化并传递您希望提供LIFO的队列类型。
EG,要创建LIFO线程池执行程序,可以使用以下构造函数。
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
并作为最终参数传入LIFO队列。
我知道java集合中没有LIFO队列(请纠正我,如果错误的话),但是您可以轻松创建一个匿名内部类来扩展LinkedBlockingQueue并覆盖相应的方法。
例如,(未测试的)
ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 16, 1, TimeUnit.MINUTES, new LinkedBlockingQueue() {
@Override
public void put(Object obj) {
// override to put objects at the front of the list
super.addFirst(obj);
}
});
UPDATE响应于评论。
我们可以使用封装优先队列的阻塞队列。我们必须打包,因为Executor期望可运行,但我们也需要时间戳。
// the class that will wrap the runnables
static class Pair {
long timestamp;
Runnable runnable;
Pair(Runnable r) {
this.timestamp = System.currentTimeMillis();
this.runnable = r;
}
}
ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 16, 1, TimeUnit.MINUTES, new BlockingQueue<Runnable>() {
private Comparator comparator = new Comparator<Pair>() {
@Override
public int compare(Pair arg0, Pair arg1) {
Long t1 = arg0.timestamp;
Long t2 = arg1.timestamp;
// compare in reverse to get oldest first. Could also do
// -t1.compareTo(t2);
return t2.compareTo(t1);
}
};
private PriorityBlockingQueue<Pair> backingQueue = new PriorityBlockingQueue<Pair>(11, comparator);
@Override
public boolean add(Runnable r) {
return backingQueue.add(new Pair(r));
}
@Override
public boolean offer(Runnable r) {
return backingQueue.offer(new Pair(r));
}
@Override
public boolean offer(Runnable r, long timeout, TimeUnit unit) {
return backingQueue.offer(new Pair(r), timeout, unit);
}
// implement/delegate rest of methods to the backing queue
});
ThreadPoolExecutor
有一个constructor它允许指定要使用的队列类型。您可以在其中插入任何BlockingQueue
,并且可能有一个priority队列可能非常适合您。您可以将优先级队列配置为基于添加到您下载作业的(创建)时间戳进行排序,并且执行程序将按照所需顺序执行作业。
按时间戳排序会很棒。将挖掘到,并尝试使其工作:) – pumpkee 2011-05-24 09:46:05
你可以做到这一点在两个或三个简单的步骤:
创建一个LifoBlockingDeque
类:
public class LifoBlockingDeque <E> extends LinkedBlockingDeque<E> {
@Override
public boolean offer(E e) {
// Override to put objects at the front of the list
return super.offerFirst(e);
}
@Override
public boolean offer(E e,long timeout, TimeUnit unit) throws InterruptedException {
// Override to put objects at the front of the list
return super.offerFirst(e,timeout, unit);
}
@Override
public boolean add(E e) {
// Override to put objects at the front of the list
return super.offerFirst(e);
}
@Override
public void put(E e) throws InterruptedException {
//Override to put objects at the front of the list
super.putFirst(e);
}
}
创建执行人:
mThreadPool = new ThreadPoolExecutor(THREAD_POOL_SIZE,
THREAD_POOL_SIZE, 0L,
TimeUnit.MILLISECONDS,
new LifoBlockingDeque<>());
LinkedBlockingDeque
仅受API级别9支持。要在早期版本上使用,请执行以下操作:
使用Java 1.6实现 - 从here下载它。
然后改变
implements BlockingDeque<E>
到
implements BlockingQueue<E>
为了让编译Android上。 BlockingDeque
是BlockingQueue
的子类型,所以没有造成任何伤害。
你完成了!
太棒了!只需将其修复为'mThreadPool = new ThreadPoolExecutor(THREAD_POOL_SIZE,THREAD_POOL_SIZE,0L,TimeUnit.MILLISECONDS,new LifoBlockingDeque
我有相同的要求:延迟加载和LIFO以获得更好的用户体验。所以我使用了ThreadPoolExecutor和一个封装的BlockingQueue(如前所述)。
为了方便向后兼容,我决定采取简单的方法,对于较老的设备,我只是使用固定线程池 - 这意味着FIFO排序。这并不完美,但第一次尝试没问题。这看起来像:
try {
sWorkQueue = new BlockingLifoQueue<Runnable>();
sExecutor = (ThreadPoolExecutor) Class.forName("java.util.concurrent.ThreadPoolExecutor").getConstructor(int.class, int.class, long.class, TimeUnit.class, BlockingQueue.class).newInstance(3, DEFAULT_POOL_SIZE, 10, TimeUnit.MINUTES, sWorkQueue);
if (BuildConfig.DEBUG) Log.d(LOG_TAG, "Thread pool with LIFO working queue created");
} catch (Exception e) {
if (BuildConfig.DEBUG) Log.d(LOG_TAG, "LIFO working queues are not available. Using default fixed thread pool");
sExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);
}
感谢您的快速响应! Unfourtunaltly LinkedBlockingQueue不附带addFirst()方法。它可能适用于LinkedBlockingDeque,但在API lvl 9之前不可用,几乎没有人安装姜饼:/无论如何。有用的答案+1。 – pumpkee 2011-05-24 09:43:39
LinkedBlockingDeque源代码可在这里找到:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/LinkedBlockingDeque.java – greg7gkb 2012-07-19 23:47:34