Android中的线程池(一)
来源:互联网 发布:java分段函数是 编辑:程序博客网 时间:2024/05/22 05:26
一直想写关于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的过程,不说思路很清晰,但是至少心中有数。
相信下一篇终极版会更加的畅快。
- Android中的线程池(一)
- android中的线程(一)
- Android中的线程(一)
- 总结:Android中的线程,线程池相关(一)---线程
- Android中的线程池和AsyncTask异步任务(一)
- Android线程与线程池(一)
- Android——线程中的通信(一)
- Android——线程中的通信(一)练习
- android 线程池(一)
- Android中的线程池
- Android中的线程池
- Android中的线程池
- Android 中的线程池
- Android中的线程池
- Android中的线程池
- Android中的线程池
- Android中的线程池
- Android中的线程池
- datatables edit 设置默认的语言
- BASIC WINDOWS PRIVILEGE ESCALATION
- JS两个数组比较,删除重复值(转)
- 第三周项目3-求集合并集
- HDU1128:Self Numbers
- Android中的线程池(一)
- Gitbook简易教程
- 【知识记录】分布式事务解决方案
- 动态规划-选学生
- Gitbook输出为静态网站并启动 (链接中有入门教程)
- 【已解决】Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
- 关于Ext3.0中按条件查询并重新加载Grid中的数据的实现过程及store.load的分析
- datatables edit 重新定义 创建 修改 删除的 URL路径
- 个人计划