FutureTaske对象(子类)属于 Runnable对象(父类接口),Thread线程有参构造器只能接收Runnable类型的对象(可以接收其子类)
    image.png
    FutureTask 未来任务 的意思
    image.png
    image.png
    三种线程创建方式的对比:
    image.png

    package com.itheima.d1_create;
    
    import javax.swing.table.TableRowSorter;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.Future;
    import java.util.concurrent.FutureTask;
    
    /**
     *  目标: 学会线程的创建方式三;实现Callable接口,结合FutureTask(未来任务)完成
     */
    public class ThreadDemo03 {
        public static void main(String[] args) {
            // 3. 创建Callable任务对象
            Callable<String> call = new MyCallable(100);
            // 4. 把Callable任务对象 交给FutureTask 对象
            // FutureTask对象任务的作用1: 是Runnable的对象(实现了Runnable接口),可以交给Thread对象了
            // futureTask对象的作用2:可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果
            // 这里就不用多态写了, 因为要调用FuntureTask的子类方法
            FutureTask<String> f1 = new FutureTask<>(call); // // 将创建的Callable任务对象 传送给  FutureTask任务对象的有参构造器
    
            // 5. 交给线程处理 (创建线程对象,交给其有参构造器)
            Thread t1 = new Thread(f1);
            // 6. 启动线程
            t1.start();
    
            /**
             * 可以再来一个线程任务  该线程计算1 - 2000 的和
             */
            // 3. 创建Callable任务对象
            Callable<String> call2 = new MyCallable(2000);
            // 4. 把Callable任务对象 交给FutureTask 对象
            // FutureTask对象任务的作用1: 是Runnable的对象(实现了Runnable接口),可以交给Thread对象了
            // futureTask对象的作用2:可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果
            // 这里就不用多态写了, 因为要调用FuntureTask的子类方法
            FutureTask<String> f2 = new FutureTask<>(call2); // // 将创建的Callable任务对象 传送给  FutureTask任务对象的有参构造器
    
            // 5. 交给线程处理 (创建线程对象,交给其有参构造器)
            Thread t2 = new Thread(f2);
            // 6. 启动线程
            t2.start();
    
    
            // 通过未来任务FutureTask的get方法来拿结果,不推荐用Callable接口对象拿结果(可能线程还没执行完)
            try {
                // 如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才会提取结果
                String rs = f1.get(); // 该结果要定义一个变量来接收,接收的变量类型和泛型接口一样
                System.out.println("第一个结果为:" + rs);
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 拿未来任务对象f2的结果
            try {
                // 如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才会提取结果
                String rs2 = f2.get(); // 该结果要定义一个变量来接收,接收的变量类型和泛型接口一样
                System.out.println("第二个结果为: " + rs2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     *  1. 定义一个任务类,实现Callable接口  应该申明线程任务执行完毕后的结果的数据类型
     *  Callable 是可呼叫的意思
     */
    class MyCallable implements Callable<String>{   // 该接口是一个泛型接口,代表有返回值类型
    
        private int n; // 定义一个 n 的值,然后通过有参构造器赋值给n
        public MyCallable(int n) { // 定义一个有参构造器 每次创建该类的对象,就会把n的值,传给该成员
            this.n = n;
        }
        /**
         *  重写call 方法 (任务方法,相当于主线程的main方法,表示要干什么)
         * @return
         * @throws Exception
         */
        @Override
        public String call() throws Exception {
            // 定义该线程任务是求一到n 的和
            int sum = 0;
            for (int i = 1; i <= n; i++) {
                sum += i;
            }
            return "子线程执行的结果是: " + sum;
        }
    }