1.继承Thread类,重写run方法。

package com.ydlclass.thread;

public class UseThread extends Thread{
    //线程创建的几种方式:1.继承Thread类,重写其run方法


    @Override
    public void run() {
        System.out.println(2);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println(1);
        new UseThread().start();//run方法与start方法的区别,start方法是启动线程的方式;如果使用run方法,结果是1,2,3.但是如果是start方法,那么可能的结果是1,3,2,
        //原因是启动线程所需要的时间比较的多。
        Thread.sleep(10);
        System.out.println(3);
        
        //启动main方法会启动一个主线程,于是打印了1,之后创建线程,由于线程启动需要时间,主线程执行完成代码之后就不再关照它;于是主线程打印了3.
        //但是我们让主线程被延迟了10ms,主线程在被创建之后就没有谁先谁后之分了。
    }
}

2.实现Runnable接口,实现run方法的方式创建线程。

3.使用匿名内部类的方式创建线程:

4.使用箭头函数(拉姆达表达式)创建线程:

package com.ydlclass.thread;

public class UseRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(2);
    }

    public static void main(String[] args) {
        System.out.println(1);
        new Thread(new UseRunnable()).start();//注意start方法是Thread实例的方法,所以我们使用实现Runnable接口的方式创建得到线程并不存在start方法,
        //这时这个线程的启动主要使用Thread类来启动,需要将Runnable的对象传输到Thread对象中,使用这个线程的有参构造来实现;

        new Thread(new Runnable() {//这就是匿名内部类的方式创建一个线程
            @Override
            public void run() {
                System.out.println(4);
            }
        }).start();

        new Thread(()-> System.out.println(5)).start();//箭头函数创建一个线程。同时这样的创建方式我们也叫做拉姆达表达式创建线程

        System.out.println(3);
    }

}

5.以上创建线程的几种方式都是简单的打印一句话,但我们存在这样的业务,线程执行完之后可能需要返回一个值,这个值用于其他的使用中;

package com.ydlclass.thread;

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

public class UseCallable implements Callable<Integer> {//实现callable接口

    @Override
    public Integer call() throws Exception {
        Thread.sleep(2000);
        return 404;
    }


    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new UseCallable());//FutureTask类是一个用于接受其他线程返回值的一个类;
        //这里为了能接受更多类型,所以使用了泛型来实现。此外,创建这个类的实例还需要一个callable类型的实例;
        new Thread(futureTask).start();//由于start方法是Thread对象才拥有的实例方法,所以这个方法的使用必不可少的需要一个Thread对象;而thread对象需要传入一个runnable
        //子类的对象,而futureTask这个类恰好是RunnableFuture的子类,而Runnable Future又恰好是Runnable的子类。
        
        Integer integer = futureTask.get();//futureTask本质上就是一个接收UseRunnable进程的一个进程。
		这个get()方法是一个阻塞方法,主函数阻塞不执行,一直等到get方法获取到值。
        System.out.println(integer);
    }
}