java Callable接口和Future接口创建线程示例详解
作者:长名06
Callable接口和Future接口
创建线程的方式
1.继承Thread类2.实现Runnable接口3.Callable接口4.线程池方式
Callable接口
在继承Thread类和实现Runnable接口的方式创建线程时,线程执行的run方法中,返回值是void,即无法返回线程的执行结果,为了支持该功能,java提供了Callable接口。
Callable和Runnable接口的区别
- 1.Callable中的call()方法,可以返回值,Runnable接口中的run方法,无返回值(void)。
- 2.call()方法可以抛出异常,run()不能抛异常。
- 3.实现Callable接口,必须重写call()方法,run是抽象方法,抽象类可以不实现。
- 4.不能用Callable接口的对象,直接替换Runnable接口对象,创建线程。
Future接口
当call()方法完成时,结果必须存储在主线程已知的对象中,以便主线程可以知道线程返回的结果,可以使用Future对象。将Future视为保存结果的对象-该对象,不一定会将call接口返回值,保存到主线程中,但是会持有call返回值。Future基本上是主线程可以跟踪以及其他线程的结果的一种方式。要实现此接口,必须重写5个方法。
public interface Future<V> {//Future源码 /** * Attempts to cancel execution of this task. This attempt will * fail if the task has already completed, has already been cancelled, * or could not be cancelled for some other reason. If successful, * and this task has not started when {@code cancel} is called, * this task should never run. If the task has already started, * then the {@code mayInterruptIfRunning} parameter determines * whether the thread executing this task should be interrupted in * an attempt to stop the task. * * <p>After this method returns, subsequent calls to {@link #isDone} will * always return {@code true}. Subsequent calls to {@link #isCancelled} * will always return {@code true} if this method returned {@code true}. * * @param mayInterruptIfRunning {@code true} if the thread executing this * task should be interrupted; otherwise, in-progress tasks are allowed * to complete * @return {@code false} if the task could not be cancelled, * typically because it has already completed normally; * {@code true} otherwise */ boolean cancel(boolean mayInterruptIfRunning); //用于停止任务,如果未启动,将停止任务,已启动,仅在mayInterrupt为true时才会中断任务 /** * Returns {@code true} if this task was cancelled before it completed * normally. * * @return {@code true} if this task was cancelled before it completed */ boolean isCancelled(); /** * Returns {@code true} if this task completed. * * Completion may be due to normal termination, an exception, or * cancellation -- in all of these cases, this method will return * {@code true}. * * @return {@code true} if this task completed */ boolean isDone();//判断任务是否完成,完成true,未完成false /** * Waits if necessary for the computation to complete, and then * retrieves its result. * * @return the computed result * @throws CancellationException if the computation was cancelled * @throws ExecutionException if the computation threw an * exception * @throws InterruptedException if the current thread was interrupted * while waiting */ V get() throws InterruptedException, ExecutionException;//任务完成返回结果,未完成,等待完成 /** * Waits if necessary for at most the given time for the computation * to complete, and then retrieves its result, if available. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument * @return the computed result * @throws CancellationException if the computation was cancelled * @throws ExecutionException if the computation threw an * exception * @throws InterruptedException if the current thread was interrupted * while waiting * @throws TimeoutException if the wait timed out */ V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Callable和Future是分别做各自的事情,Callable和Runnable类似,因为它封装了要在另一个线程上允许的任务,而Future用于存储从另一个线程获取的结果。实际上,Future和Runnable可以一起使用。创建线程需要Runnable,为了获取结果,需要Future。
FutureTask
Java库本身提供了具体的FutureTask类,该类实现了Runnable和Future接口,并方便的将两种功能组合在一起。并且其构造函数提供了Callable来创建FutureTask对象。然后将该FutureTask对象提供给Thread的构造函数以创建Thread对象。因此,间接的使用Callable创建线程。
关于FutureTask构造函数的理解
public class FutureTask<V> implements RunnableFuture<V> {//实现了RunnableFuture //该类的构造函数有两个 public FutureTask(Callable<V> callable) {// if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } //用此方法创建的线程,最后start()调用的其实是Executors.RunnableAdapter类的call(); public FutureTask(Runnable runnable, V result) {//返回的结果,就是构造函数传入的值 this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable } //原因如下 //使用FutureTask对象的方式,创建的Thread,在开启线程.start后,底层执行的是 //Thread的方法 start()方法会调用start0(),但是调用这个start0()(操作系统创建线程)的时机,是操作系统决定的,但是这个start0()最后会调用run()方法,此线程的执行内容就在传入的对象的run()方法中 public void run() { if (target != null) { target.run(); //执行到这 target就是在创建Thread时,传递的Runnable接口的子类对象,FUtureTask方式就是传入的FutureTask对象 //会执行FutureTask中的run()方法 } } //FutureTask的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(); //会执行callable的call(),callable是创建TutureTask时,根据传入的Runnable的对象封装后的一个对象 //this.callable = Executors.callable(runnable, result); 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); } } //Executors类的callable public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result); } //最后执行到这里 Executors类的静态内部类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; } } } public interface RunnableFuture<V> extends Runnable, Future<V> {//继承了Runnable, Future<V>接口 void run();// }
使用FutureTask类间接的用Callable接口创建线程
/** * @author 长名06 * @version 1.0 * 演示Callable创建线程 需要使用到Runnable的实现类FutureTask类 */ public class CallableDemo { public static void main(String[] args) { FutureTask<Integer> futureTask = new FutureTask<>(() -> { System.out.println(Thread.currentThread().getName() + "使用Callable接口创建的线程"); return 100; }); new Thread(futureTask,"线程1").start(); } }
核心原理
在主线程中需要执行耗时的操作时,但不想阻塞主线程,可以把这些作业交给Future对象来做。
- 1.主线程需要,可以通过Future对象获取后台作业的计算结果或者执行状态。
- 2.一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再获取结果。
- 3.只有执行完后,才能获取结果,否则会阻塞get()方法。
- 4.一旦执行完后,不能重新开始或取消计算。get()只会计算一次
小结
- 1.在主线程需要执行比较耗时的操作时,但又不想阻塞主线程,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态。
- 2.一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
- 3.get()方法只能获取结果,并且只能计算完后获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或抛出异常。且只计算一次,计算完成不能重新开始或取消计算。
以上就是java Callable接口和Future接口创建线程示例详解的详细内容,更多关于java Callable Future接口创建线程的资料请关注脚本之家其它相关文章!