1.why?
在程序中如果没有主动创建,只会存在一个主线程(但是在JVM中不止一个线程,还有诸如垃圾回收等)
所以为了提升性能aka加速,java开发中通常需要创建线程

2.how?
方法一:继承Thread类并重写run()

public class TestDemo{
    public static void main(String args[]) {
        new ThreadTest().start();   //新建一个实例并调用start()开始线程
    }
}
class ThreadTest extends Thread{    //创建一个继承Thread的新类
    static int[] i = {0,1,2,3};
    @Override
    public void run() {     //新线程的入口,本质上也是实现了runable接口
        for(int x:i)
        {
            System.out.println(x);
        }
    }
}

方法二:继承Runable接口并重写run()

public class TestDemo{
    public static void main(String args[]) {
        RunnableTest r = new RunnableTest();    
        new Thread(r,"thread_1").start();
        new Thread(r,"thread_2").start();
    }
}
class RunnableTest implements Runnable{
    static int[] i = {0,1,2,3};
    @Override
    public void run() {
        for(int x:i)
        {
            System.out.println(x);
        }
    }
}

方法三:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class TestDemo{
    public static void main(String args[]) {
        CallableTest c = new CallableTest();//创建 Callable 实现类的实例
        FutureTask<Integer> f = new FutureTask<>(c); //FutureTask 类来包装Callable对象,并封装返回值
        new Thread(f).start(); //使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程

        try {
           //调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
            System.out.println("子线程的返回值: " + f.get()); //FutureTask对象的get()要配合异常捕获语句使用
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
class CallableTest implements Callable{  //通过继承Callable接口创建实现类
    static int[] i = {0,1,2,3};
    @Override
    public Integer call() throws Exception{ //重写的call()方法将作为线程执行体,并且有返回值
   //throws Exception放在方法后边,表示的是本方法不处理异常,交给被调用处处理
        int t = 0;
        for(int x:i)
        {
            System.out.println(x);
            t++;
        }
        System.out.println(Thread.currentThread().getName() + " is running");
        return t;
    }
}

3.优劣比较
直接继承Thread类并重写run方法:编写简单,访问当前线程无需使用 Thread.currentThread() 方法,直接使用 this 即可;但已经继承了Thread,就不可以继承其他父类
runnable/callable:可以实现多继承,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想

runnable与callable的区别:
(1) Callable重写的是call(),Runnable重写的是run()。

(2) Callable的任务执行后可返回值,而Runnable不能。

(3) call方法可以抛出异常,run方法不可以。

(4) 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果