一 继承Thread类

实现步骤:

定义一个类(MyThread)继承Thread类
在MyThread类中重写run()方法
创建MyThread类的对象
启动线程 (对象名.start();)

1 run()和start()方法的区别

(1) 重写run()方法的原因:

run()是用来封装被线程执行的代码

(2) run()和start()方法的区别:

run():封装线程执行的代码,直接调用,相当于普通方法的调用,并没有开启线程。 (顺序执行)

start():启动线程;然后由JVM调用此线程的run()方法 (交替执行)

  • 交替:并不是某一个线程执行完了再执行另外一个线程,也不是ABAB..
    是看电脑的内部分配,谁先抢到执行权谁就先执行

二 实现Runnable接口(重点)

实现步骤:

定义一个类(MyRunnable)实现Runnable接口
在MyRunnable类中重写run()方法
创建MyRunnable类的对象
创建Thread类的对象,把MyRunnable对象作为构造方法的参数
启动线程 (对象名.start();)

  • 使用自定义类实Runnable接口比继承Thread类更加有优势
    类可以多实现(拥有多个接口的功能),但是只能单继承(只能拥有一个类的功能)多实现的拓展性就更强。

三 实现Callable接口(了解)

实现步骤:

定义一个类(MyCallable)实现Callable接口
在MyCallable类中重写call()方法
创建MyCallable类的对象
创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
创建Thread类的对象,把FutureTask对象作为构造方法的参数
启动线程 (Thread类的对象名.start();)
再调用get方法,就可以获取线程结束之后的结果(call方法的返回值)(FutureTask类的对象名.get)

public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
    for (int i = 0; i < 100; i++) {
        System.out.println("i = " + i);

    }

    return "over";
}
}
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
    //创建自定义线程对象
    MyCallable mc=new MyCallable();
    //创建FutureTask对象(需要传递Callable对象)
    FutureTask<String> task=new FutureTask<>(mc);
    //创建线程类对象
    Thread thread=new Thread(task);
    thread.start();

    for (int j = 0; j < 100; j++) {
        System.out.println("j = " + j);
    }

    //获取call()方法中的返回值数据
    String s = task.get();
    System.out.println(s);
}
}

四 三种实现方式对比

实现Runnable、Callable接口:

  • 好处:扩展性强,实现该接口的同时还可以继承其他的类
  • 缺点:编程相对复杂,不能直接使用Thread类中的方法

继承Thread类:

  • 好处:编程简单,可以直接使用Thread类中的方法
  • 缺点:扩展性较差,不能在继承其他的类
  •