Java中的线程创建方式(回顾):
-
继承Thread类创建线程类,同时重写run()方法,将需要并发执行的业务逻辑代码编写在run()方法中。
-
实现Runnable接口创建线程目标类,实现类中重写run()方法,创建Thread类的对象(有参构造器,实现类对象作为参数)。
-
实现callable接口创建线程目标类.实现call()方法(有返回值),将实现类的对象作为参数传递到FutureTask构造器中.创建FutureTask的对象,将FutureTask的对象作为参数传入Thread的构造器中创建Thread对象。
-
使用线程池创建对象
创建线程池的工具类: Executors -->创建并返回不同类型的线程池
-
Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池(缓存线程池)
-
Executors.newFixedThreadPool():创建一个可重用固定线程数的线程池
-
Executors.newSingleThreadPool():创建一个只有一个线程的线程池
-
Executors.newScheduledThreadPool():创建一个线程池,可安排在给定延迟后运行命令或者定期执行
自定义线程池:ThreadPoolExecutor构造函数
-
异步操作的有两个经典接口:Future 和 Promise,其中的 Future 表示一个可能还没有实际完成的异步任务的结果,针对这个结果可以添加 Callback 以便在任务执行成功或失败后做出对应的操作,而 Promise 交由任务执行者,任务执行者通过 Promise 可以标记任务完成或者失败。 可以说这一套模型是很多异步非阻塞架构的基础。
Future
Future模式核心思想:异步执行,同步返回
Future模式可以理解为将任务提交给线程执行,其执行结果为Future(未来的结果),期间可以去做其他事情,等需要结果时,再从Future那里get()方法阻塞等待或isDone方法轮询等待结果(获取结果,执行完直接返回结果,没有执行完则阻塞等待返回)。
JDK的Future
public interface Future<V> { // 取消异步操作 boolean cancel(boolean mayInterruptIfRunning); // 异步操作是否取消 boolean isCancelled(); // 异步操作是否完成,正常终止、异常、取消都是完成 boolean isDone(); // 阻塞直到取得异步操作结果 V get() throws InterruptedException, ExecutionException; // 同上,但最长阻塞时间为timeout V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
查看JDK中的Future接口,我们发现Future是一个只读的结构,一旦任务被提交除了取消任务外就不可能改变任务。
Future模式在JDK一般如下使用,创建对应的异步任务.然后需要结果时主动调用get方法
public static ExecutorService executorService = Executors.newFixedThreadPool(3); public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException { long start = System.currentTimeMillis(); //把耗时任务放入异步线程 FutureTask<String> task = new FutureTask<>(()->{ System.out.println(Thread.currentThread().getName()); Thread.sleep(1000L); return "test"; }); //提交任务 executorService.submit(task); //模拟耗时操作 Thread.sleep(1000L); //获取结果 String result = task.get(1000L,TimeUnit.MILLISECONDS); System.out.println(result); System.out.println(Thread.currentThread().getName() + " : " + (System.currentTimeMillis()-start)); executorService.shutdown(); }
JDK的Future的原理
从代码角度看,一个FutureTask会经历以下几个过程。
-
接受任务
FutureTask首先会接受一个Callable任务的任务,在FutureTask的构造方法中,我们看到state(自身状态)设置为NEW
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } //如果提交Runnable任务,最后也会变成callable类型 public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }
state几种状态(仅在set,setException,cancel方法中转换为终端状态)
终端状态有四种:
NORMAL
结果正常、EXCEPTIONAL
结果异常、CANCELLED
任务取消、INTERRUPTED
任务中断