java创建线程的方式

方法一:直接使用Thread

// 创建线程对象
Thread t = new Thread() {
 public void run() {
 // 要执行的任务
 }
};
// 启动线程
t.start();

例如:

public static void main(String[] args) {

        Thread t1 = new Thread("t1") {
            @Override
            // run 方法内实现了要执行的任务
            public void run() {
                System.out.println("hello");
            }
        };
        t1.start();
    }

输出:

JAVA创建thread线程 创建线程 java_创建线程

方式二:使用Runnable配合Thread

把线程和任务(要执行的代码分开)

  • Thread代表线程
  • Runnable可运行的任务(线程要执行的代码)
Runnable runnable = new Runnable() {
 public void run(){
 // 要执行的任务
 }
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
t.start();

例如:

public static void main(String[] args) {

        // 创建任务对象
        Runnable task2 = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        };
    // 参数1 是任务对象; 参数2 是线程名字,推荐
        Thread t2 = new Thread(task2, "t2");
        t2.start();
    }

结果:

JAVA创建thread线程 创建线程 java_创建线程_02

java8以后可以使用lambda精简代码

// 创建任务对象
Runnable task2 = () -> log.debug("hello");
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();

方法三:FutureTask 配合 Thread

FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况

public static void main(String[] args) {

        try {
            // 创建任务对象
            FutureTask<Integer> task3 = new FutureTask<>(() -> {
                System.out.println("hello");
                return 100;
            });
            // 参数1 是任务对象; 参数2 是线程名字,推荐
            new Thread(task3, "t3").start();
            // 主线程阻塞,同步等待 task 执行完毕的结果

            Integer result = task3.get();


            System.out.println("结果是:"+result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjcaEgbR-1652779756165)(https://gitee.com/mengyuw20/cloudimage/raw/master/img/image-20220517171738250.png)]

Thread和Runnable的关系

我们先看下Runnable的源码:

public interface Runnable {    
  public abstract void run();
}

可以看到Runnable接口就这么简单。如果没有Thread类,那么Runnable接口就是普通得不能再普通的一个接口了,我们在代码中实现这个接口,也做不了任何事情!但由于得到Thread类的“青睐”,这个接口就变得不一般了!

那么Runnable接口得到Thread类的青睐,具体表现在哪呢?我们不妨先看看Thread类的定义

public class Thread implements Runnable{}

原来Thread是Runnable的一个实现类!!!以程序人的第一直觉,那Thread自然应该实现了run方法,我们继续在源码中搜寻!

@Override
public void run() {        
  if (target != null) {
        target.run();
  }
}

果不其然,Thread实现了run方法,并且有个判断,当target为null的时候什么也不做,否则执行target的run方法,target又是什么呢?

private Runnable target;

target也是一个Runnable对象,那这个私有的字段在哪里赋值的呢?我们继续寻找发现是在init方法里面进行赋值的,并且最终在构造函数中调用了init方法,我们看看构造函数的定义(Thread重载了多个构造函数)

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

总结一下:

  • Runnable只是一个普通的接口。
  • Thread实现了Runnable接口,并且实现了接口的run方法。
  • Thread提供了重载的构造函数,接收Runnable类型的参数。在Thread重写的run方法中对调用了构造函数传入的Runnable实现类的run方法。

所以不管我们用哪种方式创建线程,都要实现或者重写run方法!并且这个run方法都是实现的Runnable接口中的方法。这个run方法就是我们自定义的需要在线程中处理的一些逻辑!

提供了重载的构造函数,接收Runnable类型的参数。在Thread重写的run方法中对调用了构造函数传入的Runnable实现类的run方法。

所以不管我们用哪种方式创建线程,都要实现或者重写run方法!并且这个run方法都是实现的Runnable接口中的方法。这个run方法就是我们自定义的需要在线程中处理的一些逻辑!