Java-宋红康-(P133-P134)-多线程创建方式(Thread and Runnable)

b站视频

133-多线程-线程创建方式1:继承Thread类_哔哩哔哩_bilibili

目录

3.1 继承Thread

3.1.1 继承Thread类方式

3.1.2 线程的执行流程

3.1.3 线程内存图

3.1.4 run()方法和start()方法

3.1.5 线程名字的设置和获取

3.1.6 获取运行main方法线程的名字

3.1.7 练习题

3.2 实现 Runable

3.2.1 实现Runnable接口方式

3.2.2 Thread和Runnable的对比

3.2.3 匿名内部类方式创建线程


3.1 继承Thread

3.1.1 继承Thread类方式

Java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。Java中通过继承Thread类来创建启动多线程的步骤如下:

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。

  2. 创建Thread子类的实例,即创建了线程对象

  3. 调用线程对象的start()方法来启动该线程

自定义线程类:

class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("自定义线程正在执行!"+i);}}
}

测试类:

public class Main {public static void main(String[] args)  throws Exception{MyThread mt=new MyThread();mt.start();for (int i = 0; i < 20; i++) {System.out.println("main线程"+i);}}
}

结果:

3.1.2 线程的执行流程

程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用mt的对象的start方法,另外一个新的线程也启动了,这样,整个应用就在多线程下运行。

通过这张图我们可以很清晰的看到多线程的执行流程,那么为什么可以完成并发执行呢?我们再来讲一讲原理。

多线程执行时,到底在内存中是如何运行的呢?以上个程序为例,进行图解说明:

多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。

3.1.3 线程内存图

当执行线程的任务结束了,线程自动在栈内存中释放了。但是当所有的执行线程都结束了,那么进程就结束了。

3.1.4 run()方法和start()方法

  • run()方法,是线程执行的任务方法,每个线程都会调用run()方法执行,我们将线程要执行的任务代码都写在run()方法中就可以被线程调用执行。

  • start()方法,开启线程,线程调用run()方法。start()方法源代码中会调用本地方法start0()来启动线程:private native void start0(),本地方法都是和操作系统交互的,因此可以看出每次开启一个线程的线程都会和操作系统进行交互。

注意:一个线程只能被启动一次!!

实例:

package test;public class TestDemo03 {public static void main(String[] args) {//创建当前Thread的子类的对象PrintNumber t1=new PrintNumber();//通过对象调用start()t1.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+i);}}
}class PrintNumber extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+i);}}
}

结果:

问题1:能否用t1.run()方法替换t1.start()的调用,实现分线程的创建和调用。

package test;public class TestDemo03 {public static void main(String[] args) {//创建当前Thread的子类的对象PrintNumber t1=new PrintNumber();//通过对象调用start()// t1.start();t1.run();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+i);}}
}class PrintNumber extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+i);}}
}

结果:(输出的全是main,通过调用run方法后变成了单线程)

3.1.5 线程名字的设置和获取

  • Thread类的方法String getName()可以获取到线程的名字。

  • Thread类的方法setName(String name)设置线程的名字。

  • 通过Thread类的构造方法Thread(String name)也可以设置线程的名字。

public class MyThread  extends Thread{public void run(){System.out.println("线程名字:"+super.getName());}
}

测试类:

public class Demo {public static void main(String[] args) {//创建自定义线程对象MyThread mt = new MyThread();//设置线程名字mt.setName("旺财");//开启新线程mt.start();}
}

注意:线程是有默认名字的,如果我们不设置线程的名字,JVM会赋予线程默认名字Thread-0,Thread-1。

3.1.6 获取运行main方法线程的名字

  • Demo类不是Thread的子类,因此不能使用getName()方法获取。

  • Thread类定义了静态方法static Thread currentThread()获取到当前正在执行的线程对象。

  • main方法也是被线程调用了,也是具有线程名字的。

public static void main(String[] args){Thread t = Thread.currentThread();System.out.println(t.getName());
} 

结果:

3.1.7 练习题

创建两个分线程,其中一个线程遍历100以内的偶数,另一个线程遍历100以内的奇数。

package test;public class TestDemo03 {public static void main(String[] args) {//创建当前Thread的子类的对象PrintNumber t1=new PrintNumber();//创建当前Thread的子类的对象PrintOddNumber t2=new PrintOddNumber();//通过对象调用start()t1.start();//通过对象调用start()t2.start();}
}//遍历100以内的偶数
class PrintNumber extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i%2==0) {System.out.println(Thread.currentThread().getName() +"--" + i);}}}
}//遍历100以内的奇数
class PrintOddNumber extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i%2==1) {System.out.println(Thread.currentThread().getName() +"--"+i);}}}
}

结果:

3.2 实现 Runable

3.2.1 实现Runnable接口方式

采用java.lang.Runnable也是非常常见的一种,我们只需要重写run方法即可。

步骤如下:

  1. 创建一个实现Runnable接口的类

  2. 实现接口中的run()方法 --> 将此线程要执行的操作,声明在此方法体中

  3. 创建Runnable实现类的实例

  4. 将此对象实例作为参数传递到Thread类的构造器中,创建Thread类的实例

  5. Thread类的实例调用start()方法:①启动线程 ②调用当前线程的run()。

package test;public class TestDemo04 {public static void main(String[] args) {//③ 创建当前实现类的对象EvenNumberPrint evenNumberPrint=new EvenNumberPrint();//④ 将此对象作为参数传递到Thread类的构造器中,创建Thread类的实例Thread t1=new Thread(evenNumberPrint);//⑤ Thread类的实例调用start():1.启动线程 2. 调用当前线程的run()方法t1.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+"---"+i);}}
}//① 创建一个实现Runnable接口的类
class EvenNumberPrint implements Runnable{//② 实现接口中的run() -->将此线程要执行的操作,声明在此方法中。@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+"---"+i);}}
}

结果:

通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个执行目标。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。

在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread对象的start()方法来运行多线程代码。

实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是继承Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的,熟悉Thread类的API是进行多线程编程的基础。

3.2.2 Thread和Runnable的对比

共同点:

  • 启动线程,使用的都是Thread类中定义的start()方法

  • 创建的线程对象,都是Thread类或其子类的实例。

不同点:

一个是类的继承,一个是接口的实现。

建议:建议使用实现Runnable接口的方式

Runnable方式的好处:

①实现的方式,可以避免类的单继承的局限性。

②更适合多个相同的程序代码的线程去共享同一个资源。

③增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

联系: public class Thread implements Runnable(代理模式)

3.2.3 匿名内部类方式创建线程

使用线程的内匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作。

使用匿名内部类的方式实现Runnable接口,重新Runnable接口中的run方法:

public class NoNameInnerClassThread {public static void main(String[] args) {                   
//                new Runnable(){
//                        public void run(){
//                                for (int i = 0; i < 20; i++) {
//                                        System.out.println("张宇:"+i);
//                                }
//                        }  
//                   }; //---这个整体  相当于new MyRunnable()Runnable r = new Runnable(){public void run(){for (int i = 0; i < 20; i++) {System.out.println("张宇:"+i);}}  };new Thread(r).start();for (int i = 0; i < 20; i++) {System.out.println("费玉清:"+i);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/210678.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不会代码(零基础)学语音开发(学习工具)

学习&#xff0c;要选择适合自己的&#xff0c;好的学习工具至关重要。就像读书&#xff0c;要读好书一样。 自己不会选&#xff0c;可以参考前辈&#xff0c;找chatgpt等来帮忙。充分利用好周边的资源。 秉承着GPT和前辈们的经验之谈&#xff0c;开始选择语音开发产品&#…

在python的Scikit-learn库中,可以使用train_test_split函数来划分训练集和测试集。

文章目录 一、在Scikit-learn库中&#xff0c;可以使用train_test_split函数来划分训练集和测试集总结 一、在Scikit-learn库中&#xff0c;可以使用train_test_split函数来划分训练集和测试集 在Scikit-learn库中&#xff0c;可以使用train_test_split函数来划分训练集和测试…

Android实验:启动式service

目录 实验目的实验内容实验要求项目结构代码实现结果展示 实验目的 充分理解Service的作用&#xff0c;与Activity之间的区别&#xff0c;掌握Service的生命周期以及对应函数&#xff0c;了解Service的主线程性质&#xff1b;掌握主线程的界面刷新的设计原则&#xff0c;掌握启…

CentOS服务自启权威指南:手动启动变为开机自启动(以Jenkins服务为例)

前言 CentOS系统提供了多种配置服务开机自启动的方式。本文将介绍其中两种常见的方式&#xff0c; 一种是使用Systemd服务管理器配置&#xff0c;不过&#xff0c;在实际中&#xff0c;如果你已经通过包管理工具安装的&#xff0c;那么服务通常已经被配置为Systemd服务&#…

5.2k Star!一个可视化全球实时天气开源项目!

大家好&#xff0c;本文给大家推荐一款全球实时天气开源项目&#xff1a;Earth。 项目简介 Earth 是一个可视化全球天气实况的项目。该项目以可视化的方式展示了全球的天气情况&#xff0c;提供了风、温度、相对湿度等多种天气数据&#xff0c;以及风、洋流和波浪的动画效果…

springboot + vue 智能物流管理系统

qq&#xff08;2829419543&#xff09;获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;springboot 前端&#xff1a;采用vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xf…

GEE:使用Roberts算子卷积核进行图像卷积操作

作者:CSDN @ _养乐多_ 本文将深入探讨边缘检测中的一个经典算法,即Roberts算子卷积。我们将介绍该算法的基本原理,并演示如何在Google Earth Engine中应用Roberts算子进行图像卷积操作。并以试验区NDVI为例子,研究区真彩色影像、NDVI图像以及卷积结果如下所示, 文章目录 …

制作一个RISC-V的操作系统五-RISC-V汇编语言编程一

文章目录 RISC-V汇编语言入门汇编语言概念简介 汇编语言语法介绍&#xff08;GNU版本&#xff09; RISC-V汇编语言入门 汇编语言概念简介 高级&#xff1a;可以理解就是更贴近人的理解 低级&#xff1a;可以理解就是更贴近机器的 难移植&#xff1a;汇编指令基本上和机器指令…

SQL Server的安装和首个库的创建

一、熟悉SQL Server的安装环境&#xff1b; 1.安装Microsoft的数据库管理系统SQL Server 2022 先把SQL Server 2022下载好后进行解压后出现以下界面然后点击基本进行安装 然后会出现以下界面&#xff1a; 一步步按照提示往下走即可&#xff0c;把SQL Server 2022安装完成后再…

微服务实战系列之Cache(技巧篇)

前言 凡工具必带使用说明书&#xff0c;如不合理的使用&#xff0c;可能得到“意外收获”。这就好比每个人擅长的领域有所差异&#xff0c;如果放错了位置或用错了人&#xff0c;也一定会让 Leader 们陷入两难之地&#xff1a;“上无法肩负领导之重托&#xff0c;下难免失去伙伴…

UDP数据报套接字

文章目录 DatagramSocket APIDatagramPacket API示例一: 请求响应UDP服务端UDP客户端 DatagramSocket API Socket是操作系统中的一个概念&#xff0c;本质上是一种特殊的文件&#xff0c;Socket就属于把“网卡”这个设备给抽象成了文件。往 Socket 文件中写数据&#xff0c;就…

【运维】hive 高可用详解: Hive MetaStore HA、hive server HA原理详解;hive高可用实现

文章目录 一. hive高可用原理说明1. Hive MetaStore HA2. hive server HA 二. hive高可用实现1. 配置2. beeline链接测试3. zookeeper相关操作 一. hive高可用原理说明 1. Hive MetaStore HA Hive元数据存储在MetaStore中&#xff0c;包括表的定义、分区、表的属性等信息。 hi…

数据库第十第十一章 恢复和并发简答题

数据库第一章 概论简答题 数据库第二章 关系数据库简答题 数据库第三章 SQL简答题 数据库第四第五章 安全性和完整性简答题 数据库第七章 数据库设计简答题 数据库第九章 查询处理和优化简答题 1.什么是数据库中的事务&#xff1f;它有哪些特性&#xff1f;这些特性的含义是什么…

CRM系统是怎样帮助销售流程自动化的?

销售业绩是衡量企业经营的重要指标&#xff0c;也是销售人员一直要达成的目标。销售业绩能否提高取决于销售人员的能力、客户服务水平&#xff0c;还需要借助有效的工具。CRM系统就是这样的一款软件。企业如何提高销售业绩&#xff1f;不妨试试CRM销售流程自动化。 CRM如何实现…

第17章 匿名函数

第17.1节 匿名函数的基本语法 [捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 { // 函数体 }语法规则&#xff1a;lambda表达式可以看成是一般函数的函数名被略去&#xff0c;返回值使用了一个 -> 的形式表示。唯一与普通函数不同的是增加了“捕获列表”。 …

11、pytest断言预期异常

官方用例 # content of test_exception_zero.py import pytestdef test_zero_division():with pytest.raises(ZeroDivisionError):1/0# content of test_exception_runtimeerror.py import pytestdef test_recursion_depth():with pytest.raises(RuntimeError) as excinfo:def…

ssm的网上奶茶店系统(有报告)。Javaee项目。

演示视频&#xff1a; ssm的网上奶茶店系统&#xff08;有报告&#xff09;。Javaee项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringMvc Mybat…

前端面试高频考点—事件循环Event loop

目录 事件循环 执行步骤 概念讲解 主线程 微任务(micro task) 宏任务(macro task) Event Loop经典例题 这段代码的执行结果是什么&#xff1f; 正确答案&#xff1a; 具体流程&#xff1a; 事件循环 主线程从"任务队列"中读取执行事件&#xff0c;这个过程…

【技术分享】RK356X Android11 以太网共享4G网络

本文基于IDO-SBC3566-V1B Android11系统实现开机后以太网自动共享4G网络功能。 IDO-SBC3566基于瑞芯微RK3566研发的一款高性能低功耗的智能主板&#xff0c;采用四核A55,主频高达1.8GHz&#xff0c;专为个人移动互联网设备和AIOT设备而设计&#xff0c;内置了多种功能强大的嵌…

android开发市场被抢占,鸿蒙能入行吗?

根据最新的数据&#xff0c;华为Mate60系列在上市第二周就成功占据了国内手机市场的17%份额&#xff0c;排名第二。而机构预测&#xff0c;华为手机在第37周有望超过20%的市场份额&#xff0c;成为国内手机市场的冠军。 一开始&#xff0c;人们对HarmonyOSNEXT持保留态度&…