一.作用概述
- 异步计算。我每天早晨起来都有很多事情要做:洗漱-煮鸡蛋-吃早餐-等等。我的步骤是起床后先煮鸡蛋,定时10分钟,再去洗漱,等我洗漱完毕在看鸡蛋是否煮好了,煮好了就开始吃早餐,没煮好则等一会。我们把洗漱完毕在煮鸡蛋叫做同步执行,把边煮鸡蛋边洗漱叫异步执行。
- 异步体现之处(看源码):客户端把FutureTask当做一个线程去执行时,会触发FutureTask的run()方法,这个时候就已经开始计算结果了;等客户端调用get()方法时候,这个结果已经计算好就把这个结果返回,没计算好get()方法阻塞。
二.UML
三.源码分析
- Future,代表异步计算的结果,5个抽象方法顾名思义。
- Runnable,线程接口,无返回值。
- Callable,代表有返回值的一个任务。
- RunnableFuture,组合了两个接口而已。
- FutureTask,实现异步计算的地方。
package java.util.concurrent; import java.util.concurrent.locks.*; //实例化FutureTask时实例化Sync public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); sync = new Sync(callable); } //实例化FutureTask时 //1.Executors.callable内部采用适配器模式适配出一个Callable对象 //2.实例化Sync public FutureTask(Runnable runnable, V result) { sync = new Sync(Executors.callable(runnable, result)); } //以下方法基本都是委托sync对象去实现 public boolean isCancelled() { return sync.innerIsCancelled(); } public boolean isDone() { return sync.innerIsDone(); } public boolean cancel(boolean mayInterruptIfRunning) { return sync.innerCancel(mayInterruptIfRunning); } public V get() throws InterruptedException, ExecutionException { return sync.innerGet(); } public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return sync.innerGet(unit.toNanos(timeout)); } protected void done() { } protected void set(V v) { sync.innerSet(v); } protected void setException(Throwable t) { sync.innerSetException(t); } //FutureTask实现了Runnable接口,当run()方法被执行的时候 public void run() { sync.innerRun(); } protected boolean runAndReset() { return sync.innerRunAndReset(); } }
- Sync类是异步计算被委托的地方,真正实现异步计算的地方。
private final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -7828117401763700385L; /** State value representing that task is running */ private static final int RUNNING = 1; /** State value representing that task ran */ private static final int RAN = 2; /** State value representing that task was cancelled */ private static final int CANCELLED = 4; /** The underlying callable */ private final Callable<V> callable; /** The result to return from get() */ private V result; /** The exception to throw from get() */ private Throwable exception; private volatile Thread runner; ...... V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException { if (!tryAcquireSharedNanos(0, nanosTimeout)) throw new TimeoutException(); if (getState() == CANCELLED) throw new CancellationException(); if (exception != null) throw new ExecutionException(exception); return result; //返回result } void innerSet(V v) { for (;;) { int s = getState(); if (s == RAN) return; if (s == CANCELLED) { // aggressively release to set runner to null, // in case we are racing with a cancel request // that will try to interrupt runner releaseShared(0); return; } if (compareAndSetState(s, RAN)) { result = v; //将callable.call()的结果赋值给result releaseShared(0); done(); return; } } } ...... //FutureTask的run方法被执行时 void innerRun() { if (!compareAndSetState(0, RUNNING)) return; try { runner = Thread.currentThread(); if (getState() == RUNNING) // recheck after setting thread innerSet(callable.call()); //调用了callable.call() else releaseShared(0); // cancel } catch (Throwable ex) { innerSetException(ex); } } }
补充一个类Executors.RunnableAdapter,将一个Runnable对象适配成一个Callable对象,显然result为空。所以可以说Runnable是一个没有返回值的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; } }
四.煮鸡蛋代码
package com.zzy.future; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; public class CookEgg { public static void main(String[] args) throws InterruptedException, ExecutionException { //1.煮鸡蛋 System.out.println("开始煮鸡蛋"); FutureTask<Egg> task = new FutureTask<Egg>(new EggCallable()); ExecutorService service = Executors.newSingleThreadExecutor(); service.execute(task); //2.洗漱8分钟 Thread.sleep(1000 * 8L); System.out.println("洗漱完毕"); System.out.println("鸡蛋煮熟没: " + task.isDone()); System.out.println(task.get().isHasCooked()); } } class EggCallable implements Callable<Egg> { @Override public Egg call() throws Exception { Thread.sleep(1000 * 10L); //鸡蛋煮10分钟 return new Egg(true); } } class Egg { private boolean hasCooked; public Egg(boolean hasCooked) { this.hasCooked = hasCooked; } public boolean isHasCooked() { return hasCooked; } }
相关推荐
(注意,本资源附带书中源代码可供参考) 多线程与并发处理是程序设计好坏优劣的重要课题,本书通过浅显易懂的文字与实例来介绍Java线程相关的设计模式概念,并且通过实际的Java程序范例和 UML图示来一一解说,书中...
本书全面解析了Java并发编程的核心概念、原理和实践,帮助读者深入理解多线程并发编程的精髓,提升编程能力和系统性能。 书中首先介绍了并发编程的基础知识,包括线程的基本概念、线程的生命周期、线程安全等问题。...
3.1多线程的团队协作:同步控制 3.2线程复用:线程池 3.3不要重复发明轮子:jdk的并发容器 3.4使用jmh进行性能测试 3.2线程复用:线程池 3.3不要重复发明轮子:JDK的并发容器 3.4使用JMH进行性能测试 实战Java高并发...
第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...
4.2.1 Java监视器模式 4.2.2 示例:车辆追踪 4.3 线程安全性的委托 4.3.1 示例:基于委托的车辆追踪器 4.3.2 独立的状态变量 4.3.3 当委托失效时 4.3.4 发布底层的状态变量 4.3.5 示例:发布状态的车辆追踪...
Java多线程入阶干货分享 1.使用线程的经验:设置名称、响应中断、使用ThreadLocal 2.Executor:ExecutorService和Future 3.阻塞队列:put和take、offer和poll、drainTo 4.线程间通信:lock、condition、wait、notify...
并发多线程从简到全 参考: 目录: [TOC] 相关文档: kwseeker/netty Executors线程池.md 1 基本概念 1.1 CPU与线程的关系 1.2 线程与进程的区别和关系 1.3 吞吐量 1.4 线程安全 1.5 线程声明周期 1.6 守护线程 1.7 ...
龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四...
java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个...
4.2.1 Java监视器模式 4.2.2 示例:车辆追踪 4.3 线程安全性的委托 4.3.1 示例:基于委托的车辆追踪器 4.3.2 独立的状态变量 4.3.3 当委托失效时 4.3.4 发布底层的状态变量 4.3.5 示例:发布状态的车辆追踪...
第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...
了解多线程所带来的安全风险.mp4 从线程的优先级看饥饿问题.mp4 从Java字节码的角度看线程安全性问题.mp4 synchronized保证线程安全的原理(理论层面).mp4 synchronized保证线程安全的原理(jvm层面).mp4 单例问题...
│ 高并发编程第二阶段21讲、多线程Future设计模式详细介绍-上.mp4 │ 高并发编程第二阶段22讲、多线程Future设计模式详细介绍-下.mp4 │ 高并发编程第二阶段23讲、第二阶段课程答疑学员问题.mp4 │ 高并发编程...
并行与并发:那么JAVA多线程实现方式:(1)继承Thread类实现多线程:(2)实现Runnable接口方式实现多线程:(3)实现callable方式:(比实现Runnable方式强大)(4)使用ExecutorService、Future(线程池):实现有返回...
Java-多线程异步请求统一响应结果 多线程异步请求是指在多个线程同时发起请求,并且在请求过程中不阻塞主线程的执行。这样可以提高程序的并发能力和响应速度。 需要注意的是,在实际的异步请求中,可能需要使用...
│ 高并发编程第二阶段21讲、多线程Future设计模式详细介绍-上.mp4 │ 高并发编程第二阶段22讲、多线程Future设计模式详细介绍-下.mp4 │ 高并发编程第二阶段23讲、第二阶段课程答疑学员问题.mp4 │ 高并发编程...