Java基础中,了解到的创建线程的两种方式为:
  • 继承Thread类
  • 实现Runnable接口

除了以上两种,还可以通过:

  • Callable接口(since JDK1.5)
  • 线程池方式

1、Callable概述

前面的Thread类或者Runnable接口方式创建线程,线程终止时,即run方法运行结束时,无法使线程返回结果,而Callable接口的优势正在于此。

【JUC】五、线程的第三种创建方式 Callable-LMLPHP

而java.lang.Runnable是void run( ) 方法:

【JUC】五、线程的第三种创建方式 Callable-LMLPHP

查看文档可以发现Thread的构造方法中,没有传Callable类型形参的,那就找个中间类:

【JUC】五、线程的第三种创建方式 Callable-LMLPHP
Thread可以传入Runnable,Runnable有个实现类叫FutureTask,它的构造方法可以传Callable,这就是个Thread和Callable的中间人。

【JUC】五、线程的第三种创建方式 Callable-LMLPHP

2、FutureTask

传入一个可调用的任务对象Callable,创建一个 FutureTask,一旦运行就执行给定的 Callable。

public FutureTask(Callable<V> callable)

关于FutureTask的理解,就是一个可取消的异步计算,单开一个线程去干其他事儿,到时候活儿干完了我在其它线程获取结果就行。这一点在之前的Runnable是实现不了的,它的run方法是void类型。

FutureTask类的常用方法

  • 取消计算,若无法取消任务,则返回 false
public boolean cancel(boolean mayInterruptIfRunning)
  • 查询计算是否完成,FutureTask正常终止、异常或取消而完成均返回true
public boolean isDone()
  • 获取计算结果
public V get()
//重载,可传入一个最大等待时间

写个demo:

/**
 * Runnable
 */
class MyThread1 implements Runnable{
    @Override
    public void run() {

    }
}

/**
 * Callable
 */
class MyThread implements Callable<String>{
    @Override
    public String call() throws Exception {
        return "200";
    }
}
public class Demo1 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        FutureTask<String> futureTask1 = new FutureTask<>(new MyThread());
        
        FutureTask<String> futureTask2 = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName() + " --> come in callable");
            return "1024";
        });
        
        new Thread(futureTask2,"t1").start();
        
        while (!futureTask2.isDone()){   //futuretask2未计算完成前,一直打印wait....
            System.out.println("wait.......");
        }
        
        System.out.println(futureTask2.get());  //在主线程中首次获取futuretask2所在线程的计算结果
        
        System.out.println(futureTask2.get());   //第二次获取计算结果
        
        System.out.println(Thread.currentThread().getName() + " --> come over");
    }
}

运行:

【JUC】五、线程的第三种创建方式 Callable-LMLPHP

在其他FutureTask所在线程中获取下另外FutureTask所在线程的计算结果:

/**
 * Callable
 */
class MyThread2 implements Callable<String>{
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName() + " --> come in callable");
        return "200";
    }
}
public class Demo1 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        FutureTask<String> futureTask1 = new FutureTask<>(new MyThread2());
        FutureTask<String> futureTask2 = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName() + " --> come in callable");
            System.out.println("在futureTask1所在线程中获取futureTask1所在线程的计算结果:" + futureTask1.get());
            return "1024";
        });

        new Thread(futureTask1,"t1").start();
        new Thread(futureTask2,"t2").start();

        System.out.println("在main线程中获取futureTask1所在线程的计算结果:" + futureTask1.get());
        System.out.println("在main线程中获取futureTask2所在线程的计算结果:" + futureTask2.get());
        System.out.println(Thread.currentThread().getName() + " --> come over");
    }
}

运行:

【JUC】五、线程的第三种创建方式 Callable-LMLPHP

11-15 02:32