线程的四种创建方式

第一种:继承Thread类

// 1.创建一个继承 Thread 的类
class MyThread extends Thread {
    // 2.重写 Thread 的 run() 方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) System.out.println(i);
    }
}

public class Test {
    public static void main(String[] args) {
        // 3.创建 Thread 的子类对象
        MyThread myThread = new MyThread();
        // 4.调用子类对象的 start() 方法
        myThread.start();
    }
}

Thread 类中的两个重要的方法(其他的方法都很简单,见名知意):

  • yield()主动放弃执行权,让 CPU 随便再选一个线程来执行(当然可能 CPU 还是会选中我)。

  • join()让贤,在 A 线程中调用 B.join() ,相当于主动让 B 线程排到自己前面去,自己则一直等到 B 执行完才继续执行(进入阻塞状态直到 B 线程执行结束)。

第二种:实现Runnable接口

// 1.创建一个实现 Runnable 接口的类
class MyRunnable implements Runnable {
    // 2.实现 Runnable 的抽象 run() 方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) System.out.println(i);
    }
}

public class Test {
    public static void main(String[] args) {
        // 3.创建实现了 Runnable 的类的对象
        MyRunnable myRunnable = new MyRunnable();
        // 4.把此对象作为参数放入 Thread 类的构造器,从而创建 Thread 类的对象
        Thread thread = new Thread(myRunnable);
        // 5.调用 Thread 类的对象的 start() 方法
        thread.start();
    }
}

相比于继承 Thread 类的方式,用实现 Runnable 接口的方式更好,原因有二:

  • Java 是单继承多实现,继承了 Thread 就不能继承别的类了(那岂不是所有自己写的子类都没法用于多线程了吗?),但实现了 Runnable 却可以同时实现别的接口。
  • 用一个 Runnable 实现类的对象就可以创建多个线程(这些线程共享这个对象),因而可以很方便地让多个线程共享数据(各个线程共享同一个 Runnable 类型的对象)。

第三种:实现Callable接口

// 1.创建一个实现 Callable 接口的类
class MyCallable implements Callable<Integer> {
    // 2.实现 Callable 的抽象 call() 方法
    @Override
    public Integer call() throws Exception {  // Callable 的 call() 方法可以抛出异常
        int sum = 0;
        for (int i = 0; i < 100; i++) sum += i;
        return sum;  // Callable 的 call() 方法可以有返回值
    }
}

public class Test {
    public static void main(String[] args) {
        // 3.创建实现了 Callable 的类的对象
        MyCallable myCallable = new MyCallable();
        // 4.把此对象作为参数放入 FutureTask 类的构造器,从而创建 FutureTask 类的对象
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        // 5.把 FutureTask 类的对象作为参数放入 Thread 类的构造器,从而创建 Thread 类的对象
        Thread thread = new Thread(futureTask);
        // 6.调用 Thread 类的对象的 start() 方法
        thread.start();
        // 7.调用 FutureTask 类的对象的 get() 方法,以获取线程的返回值(如果不需要返回值则不需要这一步)
        try {
            Object sumObject = futureTask.get();  // 获取线程的返回值
            System.out.println(sumObject);
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}

CallableRunnable 的主要区别:

  • Callablecall() 方法可以有返回值。
  • Callablecall() 方法可以抛异常。
  • Callable 支持泛型。

第四种:使用线程池

// 1.创建一个实现 Runnable 接口的类
class MyRunnable implements Runnable {
    // 2.实现 Runnable 的抽象 run() 方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) System.out.println(i);
    }
}

public class Test {
    public static void main(String[] args) {
        // 3.创建 ExecutorService 类的对象(创建线程池)
        ExecutorService executorService = Executors.newFixedThreadPool(10);  // 固定线程数量的线程池
        // 4.创建实现了 Runnable 的类的对象
        MyRunnable myRunnable = new MyRunnable();
        // 5.把实现了 Runnable 的类的对象作为参数放入 ExecutorService 类的对象的 execute() 方法
        executorService.execute(myRunnable);  // Runnable 用 execute() 方法,Callable 用 submit() 方法
        // 6.关闭线程池
        executorService.shutdown();
    }
}

终极结论

线程的创建看起来有四种方式: 继承 Thread 类、实现 Runnable 接口、实现 Callable 接口、使用线程池。

但是!!!

本质上,线程的创建方式其实只有一种:

new 一个 Thread 对象,并给它一个 Runnable 类型的对象

Thread 对象负责启动线程,Runnable 对象负责执行线程

至于具体的原因,涉及到源码,想了解的话可以看这篇文章中的详细分析:彻底理解Java线程的创建 深入源码 生动分析

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZBH4444

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值