创建线程方法一 
创建一个类去继承Thread 类
public class MyThread extends Thread {
    @Override
    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+":"+"这里是子线程");
        }
    }
}其中,Thread 类实现了 Runnable 接口
Runnable 接口只有一个方法,并且是一个函数式接口
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}创建完类之后,我们不能直接创建MyThread 对象进行调用run()
而是,调用Thread 类里的start() 方法
new MyThread().start();这样,我们就开启了一个线程,并且执行线程中的方法
创建线程方法二 
第二种是接口 Runnable
自己创建一个类 去实现Runnable 接口,重新run 方法
public class MyThread extends Runnable  {
    @Override
    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+":"+"这里是子线程");
        }
    }
}new Thread(new MyThread).start();// 通过这种方法是去调用线程启动这里其实是需要一个Runnable 子类去实现它的方法,因此,我们可以使用匿名内部类或者 jdk1.8 Lambda 表达式
public class Test{
    public static void main(String[] args) {
    	Runnable  r = ()->{
            // 这里是我们需要重新run方法的实际内容
        }
        new Thread(r).start();// 通过这种方法是去调用线程启动
    }
}创建线程方法三 
实现 callable 的接口
创建线程方法四(线程池) 
newCachedThreadPool 
根据我们的任务数量,创建线程
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();使用Executors 来创建各种各样的线程池
其中,要让线程池中的线程执行任务,则调用 execute() 方法和 submit()方法
execute()和submit() 的区别
传入类型不同
void execute(Runnable command);只接受实现了 Runnable 接口的类
而submit() 可以有三种重载形式
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);返回值
execute() 没有返回值
而submit(Callable<T> task); 有返回值 返回对象 Future
如果我们需要获取返回值 则调用Future 中的 get()方法
submit(Runnable task); 没有返回值,就算使用Future 中的get()方法也只会返回 null
submit(Runnable task, T result); 这种 会返回 result 的值
细节方面,execute()可以抛出异常和正常处理
而submit() 只要不调用获取返回值,都会吃掉异常
newFixedThreadPool 
这种线程池可以指定线程的数量
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);其中执行线程的方法与上面的一样,可参考上面的代码
newScheduledThreadPool 
根据名称可得这个是个可以延迟时间来执行线程任务的线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);这里的返回值,不要用父类 ExecutorService 因为父类里面没有 ScheduledExecutorService 里的延迟方法,
Runnable runnable = ()->{
            System.out.println("1111");
        };
scheduledThreadPool.schedule(runnable,5,TimeUnit.SECONDS);第二个参数是延迟的时间,第三个参数是延迟时间的单位
newSingleThreadExecutor() 
单线程执行池
