返回顶部
首页 > 资讯 > 前端开发 > node.js >创建线程的三种基本方法
  • 489
分享到

创建线程的三种基本方法

2024-04-02 19:04:59 489人浏览 八月长安
摘要

这篇文章主要讲解了“创建线程的三种基本方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“创建线程的三种基本方法”吧!挺基础的知识,一开始不是很愿意写,毕竟这

这篇文章主要讲解了“创建线程的三种基本方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“创建线程的三种基本方法”吧!

挺基础的知识,一开始不是很愿意写,毕竟这种简单的知识大家不一定愿意看,而且容易写的大众化,不过还好梳理一遍下来还算是有点收获,比如我看了 Thread  类重写的 run 方法,才明白为什么可以把任务(Runnable)和线程本身(Thread)分开来。

创建线程的三种方法

线程英译是 Thread,这也是 Java 中线程对应的类名,在 java.lang 包下。

注意下它实现了 Runnable 接口,下文会详细解释。

创建线程的三种基本方法

线程与任务合并 — 直接继承 Thread 类

线程创建出来自然是需要执行一些特定的任务的,一个线程需要执行的任务、或者说需要做的事情就在 Thread 类的 run 方法里面定义。

这个 run 方法是哪里来的呢?

事实上,它并不是 Thread 类自己的。Thread 实现了 Runnable 接口,run 方法正是在这个接口中被定义为了抽象方法,而 Thread  实现了这个方法。

所以,我们把这个 Runnable 接口称为任务类可能更好理解。

创建线程的三种基本方法

如下,就是通过集成 Thread 类创建一个自定义线程 Thread1 的示例:

// 自定义线程对象 class Thread1 extends Thread {     @Override  public void run() {   // 线程需要执行的任务   ......    } }  // 创建线程对象 Thread1 t1 = new Thread1();

看这里,Thread 类提供了一个构造函数,可以为某个线程指定名字:

创建线程的三种基本方法

所以,我们可以这样:

// 创建线程对象 Thread1 t1 = new Thread1("t1");

这样,控制台打印的时候就比较明了,一眼就能知道是哪个线程输出的。

当然了,一般来说,我们写的代码都是下面这种匿名内部类简化版本的:

// 创建线程对象 Thread t1 = new Thread("t1") {  @Override  // run 方法内实现了要执行的任务  public void run() {   // 线程需要执行的任务      ......   } };

线程与任务分离 — Thread + 实现 Runnable 接口

假如有多个线程,这些线程执行的任务都是一样的,那按照上述方法一的话我们岂不是就得写很多重复代码?

所以,我们考虑把线程执行的任务与线程本身分离开来。

class MyRunnable implements Runnable {     @Override     public void run() {         // 线程需要执行的任务      ......     } }  // 创建任务类对象 MyRunnable runnable = new MyRunnable(); // 创建线程对象 Thread t2 = new Thread(runnable);

除了避免了重复代码,使用实现 Runnable 接口的方式也比方法一的单继承 Thread  类更具灵活性,毕竟一个类只能继承一个父类,如果这个类本身已经继承了其它类,就不能使用第一种方法了。另外,用这种方式,也更容易与线程池等高级 api  相结合。

因此,一般来说,更推荐使用这种方式去创建线程。也就是说,不推荐直接操作线程对象,推荐操作任务对象。

上述代码使用匿名内部类的简化版本如下:

// 创建任务类对象 Runnable runnable = new Runnable() {     public void run(){         // 要执行的任务         ......     } };  // 创建线程对象 Thread t2 = new Thread(runnable);

同样的,我们也可以为其指定线程名字:

Thread t2 = new Thread(runnable, "t2");

以上两个 Thread 的构造函数如图所示:

创建线程的三种基本方法

可以发现,Thread 类的构造函数无一例外全部调用了 init 方法,这个方法到底做了啥?我们点进去看看:

创建线程的三种基本方法

它将构造函数传进来的 Runnable 对象传给了一个成员变量 target。

创建线程的三种基本方法

target 就是 Thread 类中定义的 Runnable 对象,代表着需要执行的任务(What will be run)。

这个变量的存在,就是我们能够把任务(Runnable)和线程本身(Thread)分开的原因所在。看下面这段代码:

创建线程的三种基本方法

没错,这就是 Thread 类默认实现的 run 方法。

在使用第一种方法创建线程的时候,我们定义了一个 Thread 子类并重写了其父类的 run 方法,所以这个父类实现的 run  方法不会被执行,执行的是我们自定义的子类中的 run 方法。

而在使用第二种方法创建线程的时候,我们并没有在 Thread 子类中重写 run 方法,所以父类默认实现的 run 方法就会被执行。

而这段 run 方法代码的意思就是说,如果 taget != null,也就是说如果 Thread 构造函数中传入了 Runnable 对象,那就执行这个  Runnable 对象的 run 方法。

线程与任务分离 — Thread + 实现 Callable 接口

虽然 Runnable 挺不错的,但是仍然有个缺点,那就是没办法获取任务的执行结果,因为它的 run 方法返回值是 void。

这样,对于需要获取任务执行结果的线程来说,Callable 就成为了一个完美的选择。

Callable 和 Runnable 基本差不多:

创建线程的三种基本方法

和 Runnbale 比起来,Callable 不过就是把 run 改成了 call。当然,最重要的是!和 void run 不同,这个 call  方法是拥有返回值的,而且能够抛出异常。

这样,一个很自然的想法,就是把 Callable 作为任务对象传给 Thread,然后 Thread 重写 call 方法就完事儿。

But,遗憾的是,Thread 类的构造函数里并不接收 Callable 类型的参数。

所以,我们需要把 Callable 包装一下,包装成 Runnable 类型,这样就能传给 Thread 构造函数了。

为此,FutureTask 成为了最好的选择。

创建线程的三种基本方法

可以看到 FutureTask 间接继承了 Runnable 接口,因此它也可以看作是一个 Runnable 对象,可以作为参数传入 Thread  类的构造函数。

另外,FutureTask 还间接继承了 Future 接口,并且,这个 Future 接口定义了可以获取 call() 返回值的方法 get:

创建线程的三种基本方法

看下面这段代码,使用 Callable 定义一个任务对象,然后把 Callable 包装成 FutureTask,然后把 FutureTask 传给  Thread 构造函数,从而创建出一个线程对象。

另外,Callable 和 FutureTask 的泛型填的就是 Callable 任务返回的结果类型(就是 call 方法的返回类型)。

class MyCallable implements Callable<Integer> {     @Override     public Integer call() throws Exception {         // 要执行的任务         ......         return 100;     } } // 将 Callable 包装成 FutureTask,FutureTask也是一种Runnable MyCallable callable = new MyCallable(); FutureTask<Integer> task = new FutureTask<>(callable); // 创建线程对象 Thread t3 = new Thread(task);

当线程运行起来后,可以通过 FutureTask 的 get 方法获取任务运行结果:

Integer result = task.get();

不过,需要注意的是,get 方法会阻塞住当前调用这个方法的线程。比如说我们在主线程中调用了 get 方法去获取 t3 线程的任务运行结果,那么只有这个  call 方法成功返回了,主线程才能够继续往下执行。

换句话说,如果 call 方法一直得不到结果,那么主线程也就一直无法向下运行。

启动线程

OK,综上,我们已经把线程成功创建出来了,那么怎么把它启动起来呢?

以第一种创建线程的方法为例:

// 创建线程 Thread t1 = new Thread("t1") {  @Override  // run 方法内实现了要执行的任务  public void run() {   // 线程需要执行的任务      ......   } };  // 启动线程 t1.start();

这里涉及一道经典的面试题,即为什么使用 start 启动线程,而不使用 run 方法启动线程?

使用 run 方法启动线程看起来好像并没啥问题,对吧,run 方法内定义了要执行的任务,调用 run 方法不就执行了这个任务了?

这确实没错,任务确实能够被正确执行,但是并不是以多线程的方式,当我们使用 t1.run() 的时候,程序仍然是在创建 t1 线程的 main  线程下运行的,并没有创建出一个新的 t1 线程。

举个例子:

// 创建线程 Thread t1 = new Thread("t1") {     @Override     public void run() {       // 线程需要执行的任务       System.out.println("开始执行");       FileReader.read(文件地址); // 读文件     } };  t1.run(); System.out.println("执行完毕");

如果使用 run 方法启动线程,"执行完毕" 这句话需要在文件读取完毕后才能够输出,也就是说读文件这个操作仍然是同步的。假设读取操作花费了 5  秒钟,如果没有线程调度机制,这 5 秒 CPU 什么都做不了,其它代码都得暂停。

而如果使用 start 方法启动线程,"执行完毕" 这句话在文件读取完毕之前就会被很快地输出,因为多线程让方法执行变成了异步的,读取文件这个操作是 t1  线程在做,而 main 线程并没有被阻塞。

感谢各位的阅读,以上就是“创建线程的三种基本方法”的内容了,经过本文的学习后,相信大家对创建线程的三种基本方法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: 创建线程的三种基本方法

本文链接: https://lsjlt.com/news/67667.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 创建线程的三种基本方法
    这篇文章主要讲解了“创建线程的三种基本方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“创建线程的三种基本方法”吧!挺基础的知识,一开始不是很愿意写,毕竟这...
    99+
    2024-04-02
  • Java线程的三种创建方式
    目录1、Thread2、Runnable和Thread3、Runnable和Thread4、三者对比5、注意项1、Thread 继承Thread类,并重写run方法 class ...
    99+
    2024-04-02
  • Java创建List 的三种方法
    通过 new ArrayList()  List 名称 = new ArrayList();EG: List stringList = new ArrayList();// 这种方法就是用add来添加 .add(类型的数据)// 拿到方法...
    99+
    2023-09-21
    java
  • Python中多线程的创建及基本调用方法
    1. 多线程的作用 简而言之,多线程是并行处理相互独立的子任务,从而大幅度提高整个任务的效率。 2. Python中的多线程相关模块和方法 Python中提供几个用于多线程编程的模块,包括thread,th...
    99+
    2022-06-04
    多线程 方法 Python
  • java创建线程的两种方法区别
    在Java中创建一个线程有两种方法:继承Thread类和实现Runnable接口。下面通过两个例子来分析两者的区别:1)继承Thread类public class TestThread extends Thread { int count...
    99+
    2023-05-31
    java 创建线程 ava
  • java  多线程的三种构建方法
    java  多线程的三种构建方法继承Thread类创建线程类public class Thread extends Object implements Runnable...
    99+
    2023-05-31
    java 多线程 bs
  • 创建Java线程安全类的七种方法
    目录前言无状态没有共享状态消息传递不可变状态使用来自 java.util.concurrent 的数据结构同步块易失性领域总结前言 几乎每个 Java 应用程序都使用线程。像 Tom...
    99+
    2024-04-02
  • pandas创建series的三种方法小结
    目录pandas创建series方法创建方法一Series 创建方法二Series 创建方法三Pandas的Series常用方法1. 创建Series2. Series追加3. Se...
    99+
    2024-04-02
  • JAVA实现线程的三种方法
    (1)继承Thread类,重写run函数创建:class xx extends Thread{  public void run(){Thread.sleep(1000) ...
    99+
    2022-11-15
    JAVA 线程
  • Java线程的创建方法
    这篇文章主要讲解了“Java线程的创建方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java线程的创建方法”吧!多线程指的是一个程序运行时,会包含多个线程同时进行。Java创建线程有三种...
    99+
    2023-06-02
  • 一文搞懂Java创建线程的五种方法
    目录题目描述解题思路代码详解第一种 继承Thread类创建线程第二种:实现Runnable接口创建线程第三种:实现Callable接口,通过FutureTask包装器来创建Threa...
    99+
    2024-04-02
  • java创建多线程的七种方式
    一、继承Thread,重写run方法 通过自定义一个类(这里起名为:MyThread),继承Thread类,重写run方法,最后在main方法中new出MyThread实例,调用这个实例的继承的Thread类的start方法创建一个线程。 ...
    99+
    2023-09-26
    java
  • Java 中创建线程的几种方式
    Java 是一种面向对象的编程语言,它支持多线程编程。多线程编程是指在一个程序中同时运行多个线程,这些线程可以并行执行,以提高程序的效率和性能。Java 提供了多种创建线程的方法,本文将介绍这些方法以...
    99+
    2023-09-13
    java jvm servlet
  • MySQL中创建表的三种方法汇总
    目录CREATE TABLECREATE TABLE … LIKECREATE TABLE … SELECT总结SQL 标准使用 CREATE TABLE 语句创建数据表;mysql ...
    99+
    2023-02-18
    MySQL创建表 MySQL创建表的方法 MySQL表创建
  • 【创建索引的三种方式】
    创建索引的三种方式 第一种方式:在执行 CREATE 第二种方式:使用 ALTER TABLE 命令去增加索 ALTER TABLE table_name ADD INDEX index_name ...
    99+
    2023-09-02
    数据库 mysql sql
  • 详解Java线程池的使用(7种创建方法)
    目录 1. 固定数量的线程池a.  线程池返回结果b. ⾃定义线程池名称或优先级2. 带缓存的线程池3. 执⾏定时任务 a.&nbs...
    99+
    2023-03-24
    Java线程池 Java线程池使用 线程池
  • Java线程创建的四种方式总结
    多线程的创建,方式一:继承于Thread类 1.创建一个继承于Thread类的子类 2.重写Thread类的run()--->将此线程执行的操作声明在run()中 3.创建Th...
    99+
    2024-04-02
  • Java基础之多线程方法状态和创建方法
    目录Java之线程的五大状态及其常用方法(六个状态还有timed_wating超时等待)1.线程的五大状态及其转换 2.设置或获取多线程的线程名称的方法 3.线程休眠------sl...
    99+
    2024-04-02
  • mysql 创建索引的三种方式
    1、使用CREATE INDEX创建,语法如下: CREATE INDEX indexName ON tableName (columnName(length)); 2、使用ALTER语句创建,语法如下: ALTER TABLE ...
    99+
    2023-09-07
    mysql
  • Java基础之多线程的三种实现方式
    目录一、前言二、继承Thread类实现多线程三、Runnable接口方式实现多线程四、Thread和Runnable的关系五、使用ExecutorService、Callable、F...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作