线程学习二:线程池执行Runnable与Callable
来源:互联网 发布:如何招聘php程序员 编辑:程序博客网 时间:2024/06/05 22:36
1、了解线程池几个类之间的关系 (结合图看后面的分析)
FutureTask 继承 RunnableFuture , RunnableFuture 实现接口 Runnable
2、分析常用调用线程池代码(以下称为代码A)
ExecutorService es = Executors.newFixedThreadPool(15);es.submit(new Callable<String>(){@Overridepublic String call() throws Exception {return null;}});es.submit(new myThread());
1)首先我们看看Executors.newFixedThreadPool()这个方法的源码
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }
可以看到,它实际返回的是ThreadPoolExecutor对象es
2)再看看es.submit()这个方法是如何实现的
在源码中,我们会发现ThreadPoolExecutor并没有方法submit,它是调用了父类abstractExecutorService.submit()方法,源码如下
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); } protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); } public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; } public <T> Future<T> submit(Runnable task, T result) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task, result); execute(ftask); return ftask; } public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; }
可以看到,abstractExecutorService是把Callable<T> 对象和 Runnable对象转换为了RunnbaleFuture<T>的实现类 FutureTask<T>,然后调用execute()方法。
而ThreadPoolExecutor类中是重写了execute()方法的,所以代码A中的es.submit实际上执行的是ThreadPoolExecutor.executor().
3)了解Callable 与 Runnable转换为FutureTask<T> (这里不截源码了) 与 FutureTask的run方法。
FutureTask<T>中有个Callable<T>属性,如果是Callable转,那么直接赋值就好了,如果是Runnable转,那么Eexcutors中有个类RunnableAdapter,将Runnable对象赋值给一个RunnableAdapter对象ra,然后把ra赋值给FutureTask中的Callable属性就好了。
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; } }FutureTask<T>通过父类RunnableFuture也是实现了Runnable接口的 , 所以执行也是start方法 。 run源码
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, 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); } }结果还是把Callable的call()方法丢到了Runnable的run()方法中 ,
看到里面的set(result)没有,就是通过一个全局变量,变相的返回线程执行结果,获取是FutureTask.get()方法。
4)再看看ThreadPoolExecutor.executor()是如何实现的 ,具体后续分析
<span style="color:#000000;"> 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); }</span>
上面的addWorker(COMMAND,FLAG)方法中,满足条件会构建new Thread(FutureTask) t,调用t.start();
逻辑图
5)终于到最后了,可以说我最想说的话了 。
之前没看代码,狗日的以为Callable是个很神奇的东西,就是Thread的兄弟,使用起来也挺神秘,只见过再ExecutorService.submit()见到过 。
现在才知道,Callable仅仅只是为线程执行的时候能够返回对象,且仅仅只能在ExecutorService.submit()中使用,其他无卵用。
绕来绕去还是Thread与Runnable的start方法与run方法啊。
- 线程学习二:线程池执行Runnable与Callable
- Java多线程Thread,Runnable, Callable<>和线程池(二)
- java 线程 --- Thread,Runnable,Callable 基础学习
- 线程并发学习----Thread、Runnable、Callable
- Android线程—Callable与Runnable
- 再说Runnable、Callable、Future、线程池
- java线程:callable和Runnable
- Android之多线程解析(二)之Runnable、Callable、FutureTask
- 线程池与Callable更配哦
- Java多线程Thread,Runnable, Callable<>和线程池(一)
- java 线程 接口 Callable 和Runnable
- Java线程之Runnable,Callable,FutureTask
- Java 线程之Thread,Runnable,Callable<T>
- 线程学习二 ----通过实现Runnable接口
- Callable拿到线程执行结果
- Thread--01在线程池使用Callable和Runnable的区别以及如何关闭线程
- 线程的初步理解,生命周期,实现方法,Thread类,Runnable接口,Callable接口线程池
- Java 多线程(二)——创建线程(Thread、Runnable、Callable)
- mfc 中静态控件static 的双击响应事件
- android笔记之百度地图详情页展示
- 【codeforce Gym 100570B】【最短路SPFA】 ShortestPath Query 【询问单源最短路径,每条边有一个颜色,要求路径上相邻边的颜色不能相同】
- 兼容IE8/Chrome的autocomplete
- 设计模式-读书笔记-10/14
- 线程学习二:线程池执行Runnable与Callable
- Linux系统中的环境变量知识详解
- c++使用libpcre捕获多行数据
- 欢迎使用CSDN-markdown编辑器
- jsp重写Url
- Unity移动端手势操作——3种手势互斥判断
- 进程
- Phonegap desktop app入门
- block,inline和inline-block的概念和区别