2.1 Thread类和Runnable接口
2.1.1 继承Tread类
首先是继承Tread类:
/**
* @author :ls
* @date :Created in 2022/4/18 15:10
* @description:
*/
public class T1 {
    public static class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("MyThread!");
        }
    }
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}
注意要调用 start() 方法后,该线程再算启动。
2.1.2 实现Runnable接口
Runnable接口源码
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
我们可以使用java8函数式编程来简化一下代码:
/**
* @author :ls
* @date :Created in 2022/4/18 15:10
* @description:
*/
public class T1 {
    public static class MyThread implements Runnable {
        @Override
        public void run() {
            System.out.println("MyThread");
        }
    }
    public static void main(String[] args) {
        new Thread(new MyThread()).start();
        // Java 8 函数式编程,可以省略MyThread类
        new Thread(() -> {
            System.out.println("Java 8 匿名内部类");
        }).start();
    }
}
2.1.3 Thread类构造方法
Thread类是一个 Runnable 接口的实现类
 查看Thread类的构造方法,发现其实是简单调用一个私有的init 方法来实现初始化的。
//Thread类源码
//片段1  init方法
private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals)
//片段二  构造函数
public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}
//片段三  在init方法中初始化的 AccessControlContext
this.inheritedAccessControlContext =
        acc != null ? acc : AccessController.getContext();
//片段四  两个支持ThreadLocal的私有属性
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
解释一下 这些个参数:
- g : 线程组,指定这个线程是在哪个线程组下。
- target : 指定要执行的任务。
- name : 线程的名字,多个线程的名字是可以重复的。如不指定名字,见片段二。
- acc : 见片段三,用于初始化私有变量inheritedAccessControlContext。
- inheritThreadLocals : 可继承的 ThreadLocal ,见片段4,Thread类里面有量的私有属性来支持ThreadLocal。
一般来说我们用的最多的是:
Thread(Runnable target) 
Thread(Runnable target, String name)
2.1.3 Thread类的几个常用方法
- currentThread() : 静态方法,返回对当前正在执行的线程对象的引用。
- start() : 开始执行线程的方法,java虚拟机会调用线程内部的run()方法。
- yield() : 放弃当前线程占用的cup资源。这里需要注意的是,就算当前线程调用了yield()方法,程序在调度的时候,也还有可能继续运行这个线程。
- sleep() : 静态方法,使用当前线程睡眠一段时间。
- join() : 使用当前线程等待另一个线程执行完毕之后在继续执行,内部调用是Object类的wait()方法实现的。
2.1.4 Thread类与Runnable接口的比较
- 由于java“单继承,多实现”的特性,Runnable接口使用起来比Thread更灵活。
- Runnable接口出现更符合面向对象,将线程单独进行对象的封装。
- Runnable接口出现,降低了线程对象和线程任务的耦合性。
- 如果使用线程时不需要使用Thread类的诸多方法,显然使用Runnable接口更为轻量。
2.2 Callable、Future与FutureTask
2.2.1 Callbale接口
Callable与Runnable类似,同样是只有一个抽象方法的函数式接口。不同的是,callable提供的方法是有返回值的,而且支持泛型。
@FunctionalInterface 
public interface Callable { 
    V call() throws Exception; 
}
callable一般是配合线程池工具 ExecutorService 来使用的。通过 submit 方法来让一个 Callable接口执行。它会返回一个 Future ,通过 Future 的 get 方法可以得到返回的结果。
/**
* @author :ls
* @date :Created in 2022/4/18 22:46
* @description:
*/
public class T2 implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            // 模拟计算需要⼀秒
            Thread.sleep(1000);
            return 2;
        }
        public static void main(String args[]) throws ExecutionException, InterruptedException {
            // 使⽤
            ExecutorService executor = Executors.newCachedThreadPool();
            T2 task = new T2();
            Future<Integer> result = executor.submit(task);
            // 注意调⽤get⽅法会阻塞当前线程,直到得到结果。
            // 所以实际编码中建议使⽤可以设置超时时间的重载get⽅法。
            System.out.println(result.get());
        }
}
输出结果:
2
2.2.2 Future 接口
public abstract interface Future<V> {
    public abstract boolean cancel(boolean mayInterruptIfRunning);
    public abstract boolean isCancelled();
    public abstract boolean isDone();
    public abstract V get() throws InterruptedException, ExecutionException;
    public abstract V get(long timeout, TimeUnit unit)
         throws InterruptedException, ExecutionException, TimeoutException;
}
cancel 方法是试图取消一个线程的执行。 注意这里是试图取消,并不一定成功。因为任务可能已完成、或者一些其他因素不能取消,存在取消失败可能。
 返回值 表示“是否取消成功”
 参数 mayInterruptIfRunning 表示是否采用中断的方式取消线程。
因此为了让任务有能够取消的功能,就使用callable来代替runnable。如果为了可取消性⽽使⽤ Future 但⼜不提供可⽤的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。
2.2.3 FutureTask类
这个接口有一个实现类叫 FutureTask 。 FutureTask 是 实现的 RunnableFuture 接口的,而 RunnableFuture 接口同时继承了 Runnable 接口 和 Future 接口:
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}
Future 只是一个接口,而它里面的 cancel , get , isDone 等方法要自己实现 起来都是非常复杂的。所以JDK提供了一个 FutureTask 类来供我们使用。
/**
* @author :ls
* @date :Created in 2022/4/18 23:15
* @description:
*/
public class T3 implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // 模拟计算需要⼀秒
        Thread.sleep(1000);
        return 2;
    }
    public static void main(String args[]) throws ExecutionException, InterruptedException {
        // 使⽤
        ExecutorService executor = Executors.newCachedThreadPool();
        FutureTask<Integer> futureTask = new FutureTask<>(new T3());
        Future<?> submit = executor.submit(futureTask);
        System.out.println(futureTask.get());
    }
}
使用上与第一个Demo有一点小的区别。首先,调用 submit 方法是没有返回值的。 这里实际上是调用的 submit(Runnable task) 方法,而上面的Demo,调用的 是 submit(Callable task) 方法。
然后,这里是使用 FutureTask 直接取 get 取值,而上面的Demo是通过 submit 方 法返回的 Future 去取值。
在很多高并发的环境下,有可能Callable和FutureTask会创建多次。FutureTask能 够在高并发环境下确保任务只执行一次。
2.2.3 FutureTask的几个状态
/** 
  * state可能的状态转变路径如下: 
  * NEW -> COMPLETING -> NORMAL 
  * NEW -> COMPLETING -> EXCEPTIONAL 
  * NEW -> CANCELLED 
  * NEW -> INTERRUPTING -> INTERRUPTED 
  */
private volatile int state;   //任务的运⾏状态
private static final int NEW          = 0;    //初始状态为NEW
private static final int COMPLETING   = 1;    //完成状态/结束
private static final int NORMAL       = 2;    //正常的
private static final int EXCEPTIONAL  = 3;    //异常的
private static final int CANCELLED    = 4;    //已取消
private static final int INTERRUPTING = 5;    //打断
private static final int INTERRUPTED  = 6;    //已中断










