开发技能Java线程并发获取 Java 线程执行结果

多线程入门,我们讲述了创建线程的 3 种方式,一种是直接继承 Thread,一种是实现 Runnable 接口,另外一种是实现 Callable 接口。

前 2 种方式都有一个缺陷:在执行完任务之后无法获取执行结果。 如果需要获取执行结果,就必须通过共享变量或者线程通信的方式来达到目的,这样使用起来就比较麻烦。

Java 1.5 提供了 Callable、Future、FutureTask,它们可以在任务执行完后得到执行结果,今天我们就来详细的了解一下。

无返回值的 Runnable

由于 Runnable 的 run() 方法的返回值为 void:

public interface Runnable {
    public abstract void run();
}

所以在执行完任务之后无法返回任何结果。

有返回值的 Callable

Callable 位于 java.util.concurrent 包下,也是一个接口,它定义了一个 call() 方法:

public interface Callable<V> {
    V call() throws Exception;
}

可以看到,call() 方法返回的类型是一个 V 类型的泛型。 一般会配合ExecutorService来使用Callable。------->executorService.submit(task);

异步计算结果 Future 接口

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

一共声明了 5 个方法:

  • cancel() 方法用来取消任务,如果取消任务成功则返回 true,如果取消任务失败则返回 false。参数 mayInterruptIfRunning 表示是否允许取消正在执行却没有执行完毕的任务,如果设置 true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论 mayInterruptIfRunning 为 true 还是 false,此方法肯定返回 false,即如果取消已经完成的任务会返回 false;如果任务正在执行,若 mayInterruptIfRunning 设置为 true,则返回 true,若 mayInterruptIfRunning 设置为 false,则返回 false;如果任务还没有执行,则无论 mayInterruptIfRunning 为 true 还是 false,肯定返回 true。
  • isCancelled() 方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
  • isDone() 方法表示任务是否已经完成,若任务完成,则返回 true;
  • get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
  • get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回 null。

也就是说 Future 提供了三种功能:

  • 1)判断任务是否完成;
  • 2)能够中断任务;
  • 3)能够获取任务执行结果。

由于 Future 只是一个接口,如果直接 new 的话,编译器是会有一个 ⚠️ 警告的,它会提醒我们最好使用 FutureTask。 FutureTask 是 Future 接口的一个唯一实现类,我们在前面的例子中 executorService.submit() 返回的就是 FutureTask

代码执行注意事项

原代码
  • executorService.submit(task)开启多线程,task.call()主线程执行
  • 下述代码的TaskScheduled执行步骤:
    • 总共创建三个线程:(tasks[1]的sleep时间一致)
      • 线程123执行任务123,主线程执行任务6
      • 线程12执行任务45,主线程执行7
      • 主线程执行8
// 创建一个固定大小的线程池  
        ExecutorService executorService = Executors.newFixedThreadPool(3);  
  
        // 创建一系列 Callable       
        Callable<Integer>[] tasks = new Callable[5];  
        for (int i = 0; i < tasks.length; i++) {  
            final int index = i;  
            tasks[i] = () -> {  
                TimeUnit.SECONDS.sleep(index + 1);  
                nowDate();  
                return (index + 1) * 1000;  
            };  
        }  
  
//按顺序为任务1-8
	executorService.submit(tasks[1]);  
	executorService.submit(tasks[1]);  
	executorService.submit(tasks[1]);  
	executorService.submit(tasks[1]);  
	executorService.submit(tasks[1]);  
	tasks[1].call();  
	tasks[1].call();  
	tasks[1].call();  
Built with LogoFlowershow