Java自学之路—线程的三种启动方式

168 阅读3分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战

Hope is a good thing, maybe the best of things. And no good thing ever dies—— 《The Shawshank Redemption》

前言

Java 本身的概念还是比较多的,所以学习的开始还是要先打好基础,从一些基本的概念入手,这些都是Java的一些常识。在Java的面试中都是很重要的东西。

今天来学习线程的启动方式...

在启动线程前,我们需要记住一个知识点,一个 Thread 就是一个线程。在 Java 语言中,提到线程就要想起 Thread,线程的启动方式是离不开 Thread 类的。接下来就学习一下线程的三种启动方式。

继承 java.lang.Thread 类

这种方式有两个步骤:

  1. 重写 run() 方法
  2. 调用 start() 方法启动线程

创建一个 NewThreadTest

package start;

public class NewThreadTest {
    public static void main(String[] args) {
        // 第一种启动线程的方式
        // 步骤:
        // 1. 继承java.lang.Thread 类
        // 2. 重写 run() 方法
        // 3. 调用 start() 方法启动线程

        SubThread subThread = new SubThread();
        subThread.start();
    }
}

创建一个子类 SubThread 继承自 NewThreadTest

package start;

// 1. 继承java.lang.Thread 类
public class SubThread extends Thread {
    // 2. 重写 run() 方法

    /**
     * 启动新线程要执行的任务,放在run方法中执行
     */
    @Override
    public void run() {
     // super.run();
        while (true) {
            System.out.print("这是一个子线程类");
        }
    }
}

image.png

缺点:继承自父类,耦合性比较强

实现java.lang.Runnable 接口

和第一方法比着,实现接口的方式扩展性更强。

这种方式有三个步骤:

  1. 重写 run() 方法
  2. 将 runnable 实例交给 Thread 的构造器(因为 java.lang.Runnable 接口不是线程,所以要将它交给 Thread 的构造器)
  3. 调用 start() 方法启动线程

创建 RunnableThread

package start;

// 1. 实现Runnable接口
public class RunnableThread implements Runnable {
//    2. 重写 run() 方法

    @Override
    public void run() {
        while (true) {
            System.out.print("这是Runnable线程类");
        }
    }
}
package start;

public class NewThreadTest {
    public static void main(String[] args) {
        // 第一种启动线程的方式
        // 步骤:
        // 1. 继承java.lang.Thread 类
        // 2. 重写 run() 方法
        // 3. 调用 start() 方法启动线程

        SubThread subThread = new SubThread();
        subThread.start();

//        第二种启动线程的方式
        /**
         * 步骤:
         * 1. 实现Runnable接口
         * 2. 重写 run() 方法
         * 3. 将 runnable 实例交给 Thread 的构造器
         * 4. 调用 start() 方法启动线程
         */

//        3. 将 runnable 实例交给 Thread 的构造器
        RunnableThread runnableThread = new RunnableThread();
        Thread thread2 = new Thread(runnableThread);

//        4. 调用 start() 方法启动线程
        thread2.start();
    }
}

image.png

实现 java.util.concurrent.Callable 接口

上面我们已经学习了两种启动线程的方式,为什么还有一个 Callable 接口方式呢?

首先,我们知道线程的目的就是为了完成一个任务,很多时候我还需要关注任务的执行结果,任务完成后需要将结果返回给任务的启动着或者是传递给下一个任务,以便执行下一步的动作。换句话说 Callable 接口就是为了获取线程的执行结果。

这种方式有四个步骤:

  1. 重写 call() 方法
  2. 将callable实例交给FutureTask的构造器
  3. 将FutureTask实例交给Thread的构造器
  4. 调用start()方法启动线程

FutureTask 封装了线程执行之后的结果

futureTask.get(); // get 方法在获取到结果之前,一直阻塞

优点:即能返回结果又能抛出异常

image.png

三种方式的优先级

  1. 实现 java.lang.Runnable 接口
  2. 实现 java.util.concurrent.Callable 接口
  3. 继承 java.lang.Thread 类

结语

如果这篇文章帮到了你,欢迎点赞👍和关注⭐️。

文章如有错误之处,希望在评论区指正🙏🙏

欢迎关注我的微信公众号,一起交流技术,微信搜索 🔍 :「 五十年以后