Android中的线程池(一)

一直想写关于AsyncTask的实现原理,AsyncTask的实现是用到了线程池和消息机制的,关于Android中的消息机制我已经在博客里写过了,有兴趣的同学可以去阅读。
那这篇博客就一起来学习Android中的线程池。关于Android的线程池有2篇。

在讲解Android中的线程池前,先介绍两个和线程池相关的类,在AsyncTask的实现中也会接触到。

Callable与FutureTask

Callable是一个泛型接口,接收一个泛型参数V,内部只有一个返回值为V的call方法

public interface Callable<V> {
    V call() throws Exception;
}

我们对Runnable比较熟悉,Callable和Runnable很相似,区别是Callable的call方法有返回值,而Runnable的run方法没有返回值。
Runable是包装在Thread 内部,而Callable包装在FutureTask内部。

那就来看看FutureTask吧。从FutureTask的继承结构说起:

public class FutureTask<V> implements RunnableFuture<V> {
    //代码省略
}

FutureTask实现了RunnableFuture接口的,可RunnableFuture怎么那么像Runnable和Future的合体?Future又是什么?

那么看看RunnableFuture接口

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

果然RunnableFuture是继承自Runnable和Future的。

那么Future是什么呢?
官方文档对其的描述是这样的:

A Future represents the result of an asynchronous computation. 

而我查阅相关书籍得到了更好的描述是: Future为线程池制定了一个可管理的任务标准,它提供了对Runnable,Callable任务的执行结果进行取消,查询是否完成,获取结果,设置结果的操作。

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

}

而FaskTask作为Runnable和Future的实现类,那也就有了他们两者的能力。简单理解就是有了可以获取任务执行之后的结果等等很强大的能力。 那既然FutureTask那么强大,就继续挖掘他内部的信息吧。

从FutureTask的构造方法开始:

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

这个构造方法接收一个Callable对象,这样就在内部完成了对Callable的包装。

接着看第二个构造方法:

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

Executors调用callable方法将传入的Runnable转换为Callable并赋值给FutureTask的callable字段。
在Android中创建线程池是使用工厂方法的模式的,而这个工厂就是Executors。这个先放放,会讲到的。
先来看下Executors的callable方法的内部逻辑:

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}

如果传入的Runnable为null,则会抛出空指针异常。否则将Runnable传入RunnableAdapter的构造方法。
这个RunnableAdapter是Executors的内部类。是实现了Callable接口的。那么继续跟进RunnableAdapter看看

static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

内部的逻辑实现是用到了适配器模式,从构造方法中传入Runnable对象,然后Callable调用call方法时,实际上内部执行的是Runnable的run方法。但是在外部看来,我就是在调用Callable的call方法,call方法内部逻辑我作为调用者是不关心的。
关于适配器模式我也写过一篇博客,有兴趣的同学也可以去阅读一下。

好了,我们可以总结一下,在创建FutureTask的时候,如果注入的是Runnable,则会被Executors的callable方法转换成Callable。
如果注入的是Callable,FutureTask还是会执行Callable的任务。
也就是说无论传入Callable或Runnable,FutureTask最终执行的都是Callable的任务。

FutureTask的创建好像挺复杂的哦。其实不复杂,我觉的只是设计的巧妙而已,就是做初始化的工作嘛。

那么刚才说到FutureTask是Runnable和Future的合体,那么FutureTask一定实现了Runnable的run方法的吧,我们可以看看FutureTask的run方法内部实现:

public void run() {
    if (state != NEW ||
        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

如果FutureTask的创建是正常的话,那么
if (c != null && state == NEW)这个判断是能通过的。从这个if语句的逻辑可以知道。FutureTask调用run方法就一定会调用Callable的call方法,并将执行结果赋值给result,result也是一个泛型,从创建FutureTask那一刻已经定了。
最后会调用set方法讲result设置进去。因此我们可以通过get方法来获取run方法执行的结果, 因为run方法内部包装了call方法,更准确说是获取call方法的执行结果。这就是FutureTask设计的强大之处。

好了。讲了很多,还不知道FutureTask怎么使用呢。其实Callable和FutureTask是用于线程池的。

线程池

上面提到,线程池是使用工厂方法的模式来创建的。我们可以这样创建一个简单的线程池。

ExecutorService mExecutor = Executors.newSingleThreadExecutor();

创建一个FutureTask对象

FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
     @Override
     public Integer call() throws Exception {
           //具体逻辑
           return null;
     }
});

将FutureTask提交就行了。

mExecutor.submit(futureTask);

我们可以通过

futureTask.get();

来获取执行的结果

而至于调用submit方法提交FutureTask之后又是怎么样的呢?我们之前分析过,Callable封装在FutureTask中,call方法是在FutureTask里的run方法中调用的。那么run方法在哪里得到了执行呢?

这个要从newSingleThreadExecutor方法里开始寻找信息。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

ExecutorService只是一个接口。核心在于ThreadPoolExecutor,他是ExecutorService的实现类,他非常非常的重要。那么ThreadPoolExecutor中的submit方法就是我们的答案。

糟糕的是ThreadPoolExecutor并没有submit方法,那么只能向上寻找, ThreadPoolExecutor继承自AbstractExecutorService。AbstractExecutorService是一个抽象类。那么跟进AbstractExecutorService瞧瞧。然后就找到了submit方法。
submit有三个重载的方法,而在我们刚才的举例中传进的是FutureTask,那么我们需要了解的是这个

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

好,继续分析

RunnableFuture<Void> ftask = newTaskFor(task, null);

这行代码的意义就是保证最终传入execute方法的是RunnableFuture类型的对象。看看newTaskFor方法

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

内部调用的是FutureTask的构造方法。

好,那就看到execute方法了。传进execute方法的是RunnableFuture。

但是AbstractExecutorService并没有实现execute方法,想想也对,Execute应该让具体的子类来实现的。那么回到ThreadPoolExecutor,找到execute方法。谜底快揭晓了

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     */
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

首先我们要先回忆,刚才我们在submit方法中调用execute方法,传入的是RunnableFuture对象。
这里做了一系列的判断,RunnableFuture对象会传进addWorker方法,我们现在看到addWorker方法即可

private boolean addWorker(Runnable firstTask, boolean core) {

    //代码省略

    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

抓重点,看看传进的Runnable在哪里使用到了,在这里

w = new Worker(firstTask);
final Thread t = w.thread;

这里Worker又对Runnable进行了包装。Worker的构造方法如下:

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}

继续前进,然后w.thread取出Worker里的线程对象并赋值给t变量。

往下看addWorker方法,一系列的判断之后

if (workerAdded) {
   t.start();
   workerStarted = true;
}

在这里调用了Worker里的线程对象的start方法。那么就会执行Worker里面的run方法。如下

/** Delegates main run loop to outer runWorker. */
public void run() {
    runWorker(this);
}

run方法内部调用的runWorker方法的源码如下:

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

看到这一行代码:

Runnable task = w.firstTask

这行代码取出了Worker之前封装的Runnable对象(一开始的FutureTask),并赋值给task,继续看runWorker方法,最终……

try {
    beforeExecute(wt, task);
    Throwable thrown = null;
    try {
        task.run();
    } catch (RuntimeException x) {
        thrown = x; throw x;
    } catch (Error x) {
        thrown = x; throw x;
    } catch (Throwable x) {
        thrown = x; throw new Error(x);
    } finally {
        afterExecute(task, thrown);
    }
} 

可以看到,task(FutureTask)终于调用run方法。这就是我们一直想寻找的。我们刚开始就想知道,submit提交了FutureTask之后,FutureTask的run方法在哪里被调用了。现在终于明白了。终于海阔天空了。

呼,结束了!我们大致分析了线程池的submit,execute的过程,不说思路很清晰,但是至少心中有数。

相信下一篇终极版会更加的畅快。

<think>好的,我现在需要帮助用户了解Android线程池的实现机制,特别是Executor Framework。首先,用户的问题是关于Android线程池的实现方式,提到了Executor Framework,所以我应该重点围绕这个部分展开。 首先,我需要回忆Android线程池的相关知识。记得Android中的线程池主要是通过java.util.concurrent包中的Executor Framework来实现的,这个框架提供了系列的线程池创建和管理工具。可能涉及到ThreadPoolExecutor这个核心类,以及Executors工厂类提供的几种预定义线程池,比如FixedThreadPool、CachedThreadPool、SingleThreadExecutor等。 接下来,用户给的参考引用中有四个来源,其中引用[1]和[2]提到了使用ExecutorService、AsyncTask和Runnable来实现线程池。而引用[3]和[4]是关于SpringBoot和SpringCloud的,可能和Android无关,但需要确认是否有相关的内容可以借鉴,不过可能用户是误贴了这些内容,或者需要排除干扰。因此,我应该主要关注引用[1]和[2]的内容。 用户的问题还要求回答结构清晰,分步骤说明,并且生成相关问题。同时需要遵循系统级指令中的格式要求,比如数学公式的格式,引用标识的正确使用等。 首先,我应该解释Executor Framework在Android中的实现机制。可能需要分点说明,比如核心组件、线程池类型、任务提交方式、线程池参数等。然后结合代码示例,比如如何使用ExecutorService来创建线程池,执行任务。同时,用户提供的引用中有AsyncTask,虽然现在可能已经被弃用,但可能需要提到,并说明推荐的方式。 然后,需要确保代码示例正确,并且符合用户提供的引用中的方式,即主类文件使用ExecutorService、AsyncTask、Runnable。但AsyncTask在Android中已经过时,可能需要指出,并建议使用ExecutorService配合Handler或者LiveData来更新UI。 另外,需要检查LaTeX语法是否正确,但用户的问题中可能不涉及数学公式,不过如果有任何公式,比如参数说明中的核心数、队列容量等,可能需要用行内公式格式。 在回答过程中,需要自然地添加引用标识,比如在提到ExecutorService的时候,引用用户提供的引用[1]和[2],但需要确保引用的内容确实相关。例如,引用[1]提到的是Android线程池的经典使用方式,包括ExecutorService、AsyncTask、Runnable,这正好符合用户的问题。 可能需要注意,用户提供的引用[3]和[4]是关于SpringBoot和SpringCloud的,可能与当前问题无关,可以忽略,或者在生成相关问题的时候,如果涉及到其他框架的线程池,可以生成相关问题,但需要明确区分Android和Spring的上下文。 现在,我需要组织回答的结构: 1. 概述Executor Framework在Android中的作用。 2. 核心组件:ThreadPoolExecutorExecutors工厂类。 3. 四种预定义线程池类型及其适用场景。 4. 自定义线程池的参数配置。 5. 结合代码示例说明如何使用ExecutorService提交任务。 6. 提到AsyncTask的过时,推荐使用Executor配合其他机制更新UI。 7. 引用相关站内引用,例如方式的实现。 同时,生成相关问题,比如线程池参数如何配置、不同线程池的适用场景、AsyncTask的替代方案等。 需要确保回答符合中文,使用正确的术语,避免技术错误,比如不混淆ThreadPoolExecutorExecutors的关系,正确解释各参数的意义。 最后,检查是否符合系统级指令中的格式要求,例如代码块使用正确的语法,引用标识正确放置,没有使用Markdown格式,段落清晰,分点说明等。</think>### Android线程池实现机制(Executor Framework) Android通过Java的`java.util.concurrent`包提供**Executor框架**实现线程池管理,其核心组件是`ThreadPoolExecutor`和`Executors`工厂类。以下为关键实现机制: --- #### 1. **核心组件** - **`ThreadPoolExecutor`** 直接控制线程池参数,包括: - **核心线程数**($corePoolSize$):常驻线程数量 - **最大线程数**($maxPoolSize$):线程池可扩展的最大上限 - **任务队列**($workQueue$):存储待执行任务(如`LinkedBlockingQueue`) - **线程存活时间**($keepAliveTime$):非核心线程空闲时的存活时长[^1] - **`Executors`工厂类** 提供预定义线程池类型,简化创建过程: ```java ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4); // 固定大小线程池 ``` --- #### 2. **Android中的线程池类型** | 类型 | 特点 | 适用场景 | |-----------------------|----------------------------------------------------------------------|------------------------| | **FixedThreadPool** | 固定核心线程数,无超时机制 | CPU密集型任务 | | **CachedThreadPool** | 线程数动态扩展,空闲线程自动回收 | 短期异步任务 | | **SingleThreadPool** | 单线程顺序执行任务 | 需顺序执行的任务队列 | | **ScheduledThreadPool** | 支持定时或周期性任务 | 定时/延迟任务 | --- #### 3. **任务提交方式** - **`Runnable`接口**:无返回值任务 ```java executorService.execute(new Runnable() { @Override public void run() { // 后台逻辑 } }); ``` - **`Callable`接口**:支持返回结果 ```java Future<String> future = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "Result"; } }); ``` --- #### 4. **自定义线程池示例** 通过`ThreadPoolExecutor`配置参数: ```java int corePoolSize = 2; int maxPoolSize = 5; long keepAliveTime = 30L; TimeUnit unit = TimeUnit.SECONDS; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10); ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue ); executor.execute(task); // 提交任务 ``` --- #### 5. **与UI线程的交互** - **`AsyncTask`(已过时)**:早期用于后台任务与UI更新,但易引发内存泄漏[^2]。 - **推荐方式**:使用`ExecutorService`配合`Handler`或`LiveData`更新UI: ```java executor.execute(() -> { // 后台计算 String result = processData(); new Handler(Looper.getMainLooper()).post(() -> { textView.setText(result); // 更新UI }); }); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值