【问题标题】:Executor Service with LIFO ordering带有 LIFO 排序的执行器服务
【发布时间】:2011-05-24 08:22:59
【问题描述】:

我使用 ExecutorService 为我的应用程序编写了一个惰性图像下载器。它让我可以很好地控制在什么时间并行运行多少下载等等。

现在,我唯一的问题是,如果我提交一个任务,它会在队列的尾部 (FIFO) 结束。

有人知道如何将其更改为 LIFO 吗?

【问题讨论】:

    标签: android


    【解决方案1】:

    你可以通过两三个简单的步骤来完成:

    1. 创建一个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);
          }
      }
      
    2. 创建执行器:

      mThreadPool = new ThreadPoolExecutor(THREAD_POOL_SIZE, 
                                           THREAD_POOL_SIZE, 0L, 
                                           TimeUnit.MILLISECONDS, 
                                           new LifoBlockingDeque<Runnable>());
      
    3. LinkedBlockingDeque 仅从 API 级别 9 受支持。要在早期版本上使用它,请执行以下操作:

      使用 Java 1.6 实现 - 从 here 下载。

      那就换

      implements BlockingDeque<E>
      

      implements BlockingQueue<E>
      

      让它在 Android 上编译。 BlockingDequeBlockingQueue 的子类型,所以不会造成任何伤害。

    你就完成了!

    【讨论】:

    • 太棒了!只需将其修复为 mThreadPool = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LifoBlockingDeque&lt;Runnable&gt;()); 即可消除警告
    【解决方案2】:

    您需要指定 ExecutorService 使用的队列类型。

    通常,您可能会通过 Executors 中的静态方法检索 ExecutorService。相反,您需要直接实例化一个并传入您想要提供 LIFO 的 Queue 类型。

    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);
      }
    
    });
    

    更新以响应 cmets。

    我们可以使用包装优先级队列的阻塞队列。我们必须包装,因为 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
        });
    

    【讨论】:

    • 感谢您的快速回复!不幸的是 LinkedBlockingQueue 没有 addFirst() 方法。它可能适用于 LinkedBlockingDeque,但在 API lvl 9 之前不可用,几乎没有人安装姜饼:/ 无论如何。有用的答案 +1。
    • LinkedBlockingDeque 源代码可在此处获得:grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
    【解决方案3】:

    ThreadPoolExecutor 有一个constructor,它允许指定要使用的队列类型。您可以在其中插入任何BlockingQueue,并且可能priority 队列可能非常适合您。您可以将优先级队列配置为根据添加到下载作业的(创建)时间戳进行排序,执行器将按所需顺序执行作业。

    【讨论】:

    • 按时间戳排序会很棒。将深入研究并尝试使其发挥作用:)
    【解决方案4】:

    我有相同的要求:延迟加载和 LIFO 以获得更好的用户体验。所以我使用了带有包装的 BlockingQueue 的 ThreadPoolExecutor(如前所述)。

    为了便于向后兼容,我决定采用简单的方法,对于较旧的设备,我只是使用固定线程池 - 这意味着 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);
            }
    

    【讨论】:

      猜你喜欢
      • 2011-05-09
      • 1970-01-01
      • 2011-06-04
      • 2013-06-28
      • 1970-01-01
      • 1970-01-01
      • 2021-05-15
      • 2020-05-04
      相关资源
      最近更新 更多