美文网首页
源码翻译师1 Android-Lite-Go(Part2)

源码翻译师1 Android-Lite-Go(Part2)

作者: 小石头_Kerry | 来源:发表于2016-03-28 17:39 被阅读0次

    (2)Java Executor框架
    参考:
    Java Executor框架

    Executor框架是指java5中引入的一系列并发库中与executor相关的功能类,包括Executor、Executors、ExecutorService、CompletionService、Future、Callable等。通过学习Executor框架能够更加清楚明晰作者的写作思路和来源。


    Class Executor

    开始的开始 Executor

    public interface Executor {
        void execute(Runnable command); 
    }
    

    Executor接口是Executor框架中最基础的部分,定义了一个用于执行Runnable的execute方法。它没有直接的实现类,有一个重要的子接口ExecutorService。

    ExecutorService
    ExecutorService接口继承自Executor接口,定义了终止、提交任务、跟踪任务返回结果等方法。

    Runnable、Callable、Future

    // 实现Runnable接口的类将被Thread执行,表示一个基本的任务
    public interface Runnable {
        // run方法就是它所有的内容,就是实际执行的任务
        public abstract void run();
    }
    
    // Callable同样是任务,与Runnable接口的区别在于它接收泛型,同时它执行任务后带有返回内容
    public interface Callable<V> {
        // 相对于run方法的带有返回值的call方法
        V call() throws Exception;
    }
    
    // Future代表异步任务的执行结果
    public interface Future<V> {
    
        /**
         * 尝试取消一个任务,如果这个任务不能被取消(通常是因为已经执行完了),返回false,否则返回true。
         */
        boolean cancel(boolean mayInterruptIfRunning);
    
        /**
         * 返回代表的任务是否在完成之前被取消了
         */
        boolean isCancelled();
    
        /**
         * 如果任务已经完成,返回true
         */
        boolean isDone();
    
        /**
         * 获取异步任务的执行结果(如果任务没执行完将等待)
         */
        V get() throws InterruptedException, ExecutionException;
    
        /**
         * 获取异步任务的执行结果(有最常等待时间的限制)
         *
         *  timeout表示等待的时间,unit是它时间单位
         */
        V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
    }
    

    ScheduledFuture继承自Future和Delayed接口,自身没有添加方法。Delayed接口定义了一个获取剩余延迟的方法。

    ExecutorService有一个子接口ScheduledExecutorService和一个抽象实现类AbstractExecutorService。

    ScheduledExecutorService
    可以安排指定时间或周期性的执行任务的ExecutorService

    // 可以安排指定时间或周期性的执行任务的ExecutorService
    public interface ScheduledExecutorService extends ExecutorService {
        /**
         * 在指定延迟后执行一个任务,只执行一次
         */
        public ScheduledFuture<?> schedule(Runnable command,
                           long delay, TimeUnit unit);
        /**
         * 与上面的方法相同,只是接受的是Callable任务
         */
        public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                           long delay, TimeUnit unit);
        /**
         * 创建并执行一个周期性的任务,在initialDelay延迟后每间隔period个单位执行一次,时间单位都是unit
         * 每次执行任务的时间点是initialDelay, initialDelay+period, initialDelay + 2 * period...
         */
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                              long initialDelay,
                              long period,
                              TimeUnit unit);
        /**
         * 创建并执行一个周期性的任务,在initialDelay延迟后开始执行,在执行结束后再延迟delay个单位开始执行下一次任务,时间单位都是unit
         * 每次执行任务的时间点是initialDelay, initialDelay+(任务运行时间+delay), initialDelay + 2 * (任务运行时间+delay)...
         */
        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                 long initialDelay,
                                 long delay,
                                 TimeUnit unit);
    }
    

    AbstractExecutorService
    看到AbstractExecutorService的时候,基本就能找到一点痕迹了,LiteGo的核心代码有一些都参照了它的写法。
    我们先来了解下下面三个概念:

    • RunnableFuture继承自Future和Runnable,只有一个run()方法。RunnableFuture接口看上去就像是Future和Runnable两个接口的组合。
    public interface RunnableFuture<V> extends Runnable, Future<V> {    
            void run();
    }
    
    • FutureTask类实现了RunnableFuture接口,除了实现了Future和Runnable中的方法外,它还有自己的方法。
    • ExecutorCompletionService实现了CompletionService接口,将结果从复杂的一部分物种解耦出来。

    ThreadPoolExecutor
    ThreadPoolExecutor继承自AbstractExecutorService。

    ScheduledThreadPoolExecutor
    它继承自ThreadPoolExecutor并实现了ScheduledExecutorService接口。

    Executors
    Executors中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory
    和 Callable
    类的工厂和实用方法。

    • newFixedThreadPool
      创建一个定长的线程池。达到最大线程数后,线程数不再增长。
      如果一个线程由于非预期Exception而结束,线程池会补充一个新的线程。
    • newCachedThreadPool
      创建一个可缓存的线程池。当池长度超过处理需求时,可以回收空闲的线程。
    • newSingleThreadPool
      创建一个单线程executor。
    • newScheduledThreadPool
      创建一个定长的线程池,而且支持定时的以及周期性的任务执行。
      类似于Timer。但是,Timer是基于绝对时间,对系统时钟的改变是敏感的,而ScheduledThreadPoolExecutor只支持相对时间。

    与Timer比较

    1. Timer是创建唯一的线程来执行所有的timer任务。如果一个任务超时了,会导致其他的TimerTask时间准确性出问题。
    2. 如果TimerTask抛出uncheck 异常,Timer将会产生无法预料的行为。因此,ScheduledThreadPoolExecutor可以完全代替Timer。

    (3)LinkedList 和 ArrayList
    参考链接
    因为平时我们大多使用的是动态数组ArrayList,对LinkedList并不是那么的熟悉,这里探究一下它们的区别和源码中为什么要使用LinkedList。

    LinkedList和ArrayList都实现了List接口,但是它们的工作原理却不一样。它们之间最主要的区别在于ArrayList是可改变大小的数组,而LinkedList是双向链接串列(doubly LinkedList)。

    • 因为Array是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。Array获取数据的时间复杂度是O(1),但是要删除数据却是开销很大的,因为这需要重排数组中的所有数据。
    • 相对于ArrayList,LinkedList插入是更快的。因为LinkedList不像ArrayList一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是ArrayList最坏的一种情况,时间复杂度是O(n),而LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索引(除了插入数组的尾部)。
    • 类似于插入数据,删除数据时,LinkedList也优于ArrayList。
    • LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中存储的是实际的数据和前后节点的位置。
      在LinkedList中有一个私有的内部类,定义如下:
    private static class Entry { 
             Object element; 
             Entry next; 
             Entry previous; 
         } 
    

    这也就是LinkedList耗费内存更多的地方。

    什么场景下更适宜使用LinkedList,而不用ArrayList

    • 你的应用不会随机访问数据。因为如果你需要LinkedList中的第n个元素的时候,你需要从第一个元素顺序数到第n个数据,然后读取数据。
    • 你的应用更多的插入和删除元素,更少的读取数据。因为插入和删除元素不涉及重排数据,所以它要比ArrayList要快。

    以上就是关于ArrayList和LinkedList的差别。你需要一个不同步的基于索引的数据访问时,请尽量使用ArrayList。ArrayList很快,也很容易使用。但是要记得要给定一个合适的初始大小,尽可能的减少更改数组的大小。

    由此可见,LiteGo的使用场景中可能会出现大量的任务插入和删除(插入和删除有可能发生在列表的前面),但并不会涉及到查询,所以这里使用LinkedList是有道理的。

    相关文章

      网友评论

          本文标题:源码翻译师1 Android-Lite-Go(Part2)

          本文链接:https://www.haomeiwen.com/subject/pvvjlttx.html