深入Callable及Runnable两个接口 获取线程返回结果
来源:互联网 发布:无极门 淘宝 编辑:程序博客网 时间:2024/05/17 08:15
科技优家 2017-04-13 10:11
今天碰到一个需要获取线程返回结果的业务场景,所以了解到了Callable接口。
先来看下下面这个例子:
public class ThreadTest { public static void main(String[] args) throws Exception { ExecutorService exc = Executors.newCachedThreadPool; try { String result = null; FutureTask<String> task = (FutureTask<String>) exc.submit(new Runnable { @Override public void run { for (int i = 0; i < 10; i++) { try { Thread.sleep(100L); } catch (InterruptedException e) { e.printStackTrace; } System.out.println(this.getClass + "::线程执行中.." + i); } } }, result); System.out.println("task return value:" + task.get); FutureTask<String> callableTask = (FutureTask<String>) exc.submit(new Callable<String> { @Override public String call throws InterruptedException { for (int i = 0; i < 10; i++) { Thread.sleep(100L); System.out.println(this.getClass + "::线程执行中.." + i); } return "success"; } }); System.out.println("提前出结果了 task return value:" + task.get); System.out.println("callableTask return value:" + callableTask.get); } finally { exc.shutdown; } }}
运行结果如下:
class thread.ThreadTest$1::线程执行中..0class thread.ThreadTest$1::线程执行中..1class thread.ThreadTest$1::线程执行中..2class thread.ThreadTest$1::线程执行中..3class thread.ThreadTest$1::线程执行中..4class thread.ThreadTest$1::线程执行中..5class thread.ThreadTest$1::线程执行中..6class thread.ThreadTest$1::线程执行中..7class thread.ThreadTest$1::线程执行中..8class thread.ThreadTest$1::线程执行中..9task return value:null提前出结果了 task return value:nullclass thread.ThreadTest$2::线程执行中..0class thread.ThreadTest$2::线程执行中..1class thread.ThreadTest$2::线程执行中..2class thread.ThreadTest$2::线程执行中..3class thread.ThreadTest$2::线程执行中..4class thread.ThreadTest$2::线程执行中..5class thread.ThreadTest$2::线程执行中..6class thread.ThreadTest$2::线程执行中..7class thread.ThreadTest$2::线程执行中..8class thread.ThreadTest$2::线程执行中..9callableTask return value:success
可以得到以下几点:
1 Runnable,Callable两个接口方法体不一样,前者为run,后者为call,且返回值也不一样;
2 Runnable接口由于run方法返回void所以无法解决线程成功后返回相应结果的问题;但是实现Callable接口的线程类可以,因为Callable的执行方法体call方法
可以返回对象。
3 由于runnable接口没有返回值,所以FutureTask为了解决此问题将runnable线程类通过支配器转换为callable线程: 当通过task对象调用get方法时,已经执行完成的可以立刻得到返回结果,但是还没执行完的线程一直在等待。
下面进入源码看看:
线程池执行submit方法时进入AbstractExecutorService类中的submit
public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException; RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; }
这里好理解,将线程放入任务,由线程池的execute方法去执行。
执行完成后,当调用get方法时,会进入FutureTask的get方法:
public V get throws InterruptedException, ExecutionException { int s = state;//当线程状态为新建活着执行中时一直调用awaitDone方法 if (s <= COMPLETING)//循环判断线程状态是否已经执行成功,如果执行成功返回线程状态;其中还包括线程取消,中断等情况的判断。可参见下方源码。//所以这里便是上面例子中为什么线程执行成功后即可立即得到结果,如果还没有执行成功s = awaitDone(false, 0L);
//线程状态正常返回结果return report(s); }
awaitDone源码
private int awaitDone(boolean timed, long nanos) throws InterruptedException { final long deadline = timed ? System.nanoTime + nanos : 0L; WaitNode q = null; boolean queued = false; for (;;) { if (Thread.interrupted) { removeWaiter(q); throw new InterruptedException; } int s = state; if (s > COMPLETING) { if (q != null) q.thread = null; return s; } else if (s == COMPLETING) // cannot time out yet Thread.yield; else if (q == null) q = new WaitNode; else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); else if (timed) { nanos = deadline - System.nanoTime; if (nanos <= 0L) { removeWaiter(q); return state; } LockSupport.parkNanos(this, nanos); } else LockSupport.park(this); } }
@SuppressWarnings("unchecked") private V report(int s) throws ExecutionException { Object x = outcome; if (s == NORMAL) return (V)x; if (s >= CANCELLED) throw new CancellationException; throw new ExecutionException((Throwable)x); }
然后我们来看看FutureTask是如何对runnable线程进行转换的。代码也很简单:
public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }
public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException; return new RunnableAdapter<T>(task, result); }
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; } }
0 0
- 深入Callable及Runnable两个接口 获取线程返回结果
- Java线程池及Future、Callable获得线程返回结果
- Callable接口实现线程执行结果的返回
- JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没
- Android(Java)之多线程结果返回——Future 、FutureTask、Callable、Runnable
- java 线程 接口 Callable 和Runnable
- Callable 获取线程返回值
- Java线程池及Future、Callable获得线程返回结果【Java线程池系列2】
- 线程结果回调Runnable、Callable、Future、FutureTask
- CompletionService + Callable实现线程动态返回结果
- Callable接口与Runnable
- (五) Java多线程详解之Callable和Future阻塞获取线程返回结果
- Callable接口和Runnable接口
- Callable接口和Runnable接口
- Callable接口和Runnable接口
- Callable接口和Runnable接口
- Callable接口和Runnable接口
- Callable接口和Runnable接口
- Mondrian in action第10章 翻译
- 将博客搬至CSDN
- Altium Desinger 选择性导出BOM
- 济南学习 Day 5 T1 pm
- OpenCV玩九宫格数独(二):knn数字识别
- 深入Callable及Runnable两个接口 获取线程返回结果
- [RK3288][Android6.0] 开机播放音乐流程小结
- 一致性算法Paxos详解
- maven的java web项目启动找不到Spring ContextLoaderListener的解决办法
- 530. Minimum Absolute Difference in BST的C++解法
- Lodop打印参数方法参考
- myeclipse获取注册码
- 给拒绝过你的公司再投简历,是自取其辱?
- Oracle创建新用户一系列操作模板