并发编程 系列 任务

开启 并发编程 新篇章

Posted by lichao modified on May 16, 2020
  • Runnable
  • Callable
  • Future
    • FutureTask

Callable

Callable 接口和 Runnable 接口相似,都可以被另外一个线程执行,Runnable不会返回数据也不能抛出异常。 Java 1.5之后提供了Callable和Future接口,通过它们就可以在任务执行完毕之后得到任务的执行结果

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

 static class Task  implements Callable<Integer> {
 
     @Override
     public Integer call() throws Exception {
          System.out.println("Thread [" + Thread.currentThread().getName() + "] is running");
          int result = 0;
          for(int i = 0; i < 100;++i) {
              result += i;
          }
 
          Thread.sleep(3000);
          return result;
      }
  }

Future

FutureTask

FutureTask 既能当做一个 Runnable 直接被 Thread 执行,也能作为 Future 用来得到 Callable 的计算结果。

FutureTask 可作为可异步执行任务并可获取执行结果,通常可以使用 future.get() 来获取线程的执行结果,在线程执行结束之前 get 方法会一直阻塞状态,直到 call() 返回,其优点是使用线程异步执行任务的情况下还可以获取到线程的执行结果。

jvm

思想: 当用户实现Callable()接口定义好任务之后,把任务交给其他线程进行执行。FutureTask内部维护一个任务状态status,任何操作都是围绕着这个状态进行,并随时更新任务状态。任务发起者调用get*()获取执行结果的时候,如果任务还没有执行完毕,则会把自己放入阻塞队列waitnode中然后进行阻塞等待。当任务执行完成之后,任务执行线程会依次唤醒阻塞等待的线程。调用cancel()取消任务的时候也只是简单的修改任务状态,如果需要中断任务执行线程的话则调用Thread.interrupt()中断任务执行线程。

注:cancel(true)并不一定能够停止正在执行的异步任务。

源码解析

采用适配器模式把 runable 转换为 callable: jvm jvm