【JAVA语言-第19话】多线程详细解析(一)

目录

多线程

1.1 并发和并行 

1.2 线程和进程 

1.2.1 进程

1.2.2 线程

1.3 单线程 

1.3.1 单线程案例 

1.4 创建多线程的方式

1.4.1 继承Thread类

1.4.2 实现Runnable接口

1.4.3  使用匿名内部类

1.5 Thread类

1.5.1 构造方法

1.5.2 常用方法 

1.5.3 Thread类中的常用方法练习


多线程

        指在一个程序中同时运行多个线程,每个线程可以执行不同的任务。多线程可以提高程序的性能和响应速度,充分利用计算机的多核处理能力。同时,多线程也可以实现任务的并发执行,提升程序的效率。多线程之间可以共享数据,但也需要注意线程安全的问题。 

1.1 并发和并行 

  • 并发:指两个或多个事件在同一个时间段内发生(交替执行)。
  • 并行:指两个或多个事件在同一时刻发生(同时执行)。

1.2 进程和线程 

1.2.1 进程

        指一个内存中运行的应用程序,每一个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程,进程也是程序的一次执行过程,是系统运行程序的基本单位,系统运行一个程序即是一个进程从创建、运行到消亡的过程。

1.2.2 线程

        线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

注:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。  

1.3 单线程 

        指java程序只有一个线程(main方法的线程),执行从main方法开始,从上到下依次执行,执行过程如下:

  1. JVM执行main方法,main方法会进入到栈内存。
  2. JVM会找操作系统开辟一条main方法通向CPU的执行路径。
  3. CPU就可以通过这个路径来执行main方法。
  4. 而这个路径有一个名字,叫(main)主线程。

1.3.1 单线程案例 

场景:

        模拟王者游戏中,两组英雄进行攻击(米莱迪 攻击 诸葛亮 and 亚瑟 攻击 猪八戒),下面是采用单线程的方式实现。

Hero.java(角色类) 

package com.zhy.multiplethread;public class Hero{/*** 角色名称*/public String name;/*** 角色血量*/public float hp;/*** 攻击伤害*/public int damage;public Hero(){   }public Hero(String name,float hp,int damage){this.name = name;this.hp = hp;this.damage = damage;}/*** 角色攻击方法* @param h*/public void attackHero(Hero h) {try {//攻击需要时间,每次攻击暂停1000毫秒Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//每次攻击,角色的血量逐渐减少h.hp -= damage;System.out.format("%s 正在攻击 %s, %s 的血变成了 %.0f%n",name,h.name,h.name,h.hp);if(h.isDead()){System.out.println(h.name +" 已被击杀!");}}/*** 判断角色是否已被击杀(根据血量判断),血量>=0:返回true,否则:返回false* @return*/public boolean isDead() {return 0 >= hp ? true : false;}
}

TestThread.java(测试类) 

package com.zhy.multiplethread;public class TestThread {public static void main(String[] args) {Hero hero1 = new Hero("米莱迪",350,60);Hero hero2 = new Hero("诸葛亮",300,50);Hero hero3 = new Hero("亚瑟",450,70);Hero hero4 = new Hero("猪八戒",400,60);//米莱迪 攻击 诸葛亮while(!hero2.isDead()){hero1.attackHero(hero2);}//亚瑟 攻击 猪八戒while(!hero4.isDead()){hero3.attackHero(hero4);}}
}

输出结果:

        使用单线程实现,可以看出,第二组英雄 是在 第一组英雄攻击完毕后 才开始攻击的。

1.4 创建多线程的方式

        创建多线程的常用方式有三种,第一种是继承Thread类;第二种是实现Runnable接口;第三种是直接使用匿名内部类进行具体实现。下面我们依次进行详细解析。

1.4.1 继承Thread类

        java.lang.Thread类:Java线程模型的基础,只需要继承Thread类并重写run()方法来定义线程的执行逻辑。然后可以通过创建Thread的实例来启动线程。

实现步骤:

  1. 创建一个Thread类的子类。
  2. 在Thread类的子类中重写Thread类中的run()方法,设置线程任务(具体业务场景)。
  3. 创建Thread类的子类对象为实例。
  4. 调用Thread类中的start方法,开启新的线程,实际是执行的run()方法。

        

注意事项:

  • void start():使该线程开始执行;java虚拟机调用该线程的run()方法。
  • 启动线程后,实际是两个线程并发的运行,当前线程(main线程)和另一个线程(创建的新线程,执行其run()方法)。
  • 多次启动一个线程是非法的,特别是当线程已经结束执行后,不能在重新启动。​​​​​​ 

代码示例:  

场景:

        模拟王者游戏中,两组英雄进行攻击(米莱迪 攻击 诸葛亮 and 亚瑟 攻击 猪八戒),下面是采用多线程的方式实现。

KillThread.java(Thread的子类) 

package com.zhy.multiplethread;/*** 1.创建一个Thread类的子类。*/
public class KillThread extends Thread{private Hero h1;private Hero h2;public KillThread(Hero h1, Hero h2){this.h1 = h1;this.h2 = h2;}/*** 2.在子类中重写Thread类中的run()方法,设置线程任务。*  当角色h2没有被击杀时,角色h1持续进行攻击*/public void run(){while(!h2.isDead()){h1.attackHero(h2);}}
}

 TestThread.java(测试类) 

package com.zhy.multiplethread;public class TestThread {public static void main(String[] args) {Hero hero1 = new Hero("米莱迪",350,60);Hero hero2 = new Hero("诸葛亮",300,50);Hero hero3 = new Hero("亚瑟",450,70);Hero hero4 = new Hero("猪八戒",400,60);//3.创建Thread类的子类对象KillThread killThread1 = new KillThread(hero1,hero2);KillThread killThread2 = new KillThread(hero3,hero4);//4.调用Thread类中的start方法,开启新的线程,实际是执行的run()方法。killThread1.start();killThread2.start();}
}

输出结果:

        java程序属于抢占式调度,哪个线程的优先级高,哪个线程就先执行,同一个优先级,随机选择一个执行。从输出中可以看到,第一组英雄 还没攻击完毕 第二组英雄就开始攻击了,可以很大程度的提高程序的性能和速度。

1.4.2 实现Runnable接口

        java.lang.Runnable接口:实现Runnable接口的类可以作为Thread类的构造函数参数来创建线程。这种方式更加灵活,因为Java不支持多继承,所以实现Runnable接口可以使类在同时继承其他类的情况下创建线程。

构造方法:
        Thread(Runnable target):分配新的Thread对象。
        Thread(Runnable target,String name):分配新的Thread对象。

        

实现步骤: 

  1. 创建一个Runnable接口的实现类。
  2. 在实现类中重写Runnable接口的run方法,设置线程任务。
  3. 创建一个Runnable接口的实现类对象。
  4. 创建Thread类对象,构造方法中传递Runnable接口的实现类对象。
  5. 调用Thread类中的start方法,开启新的线程执行run方法。

代码示例: 

场景同上 

Battle.java(Runnable的实现类)

package com.zhy.multiplethread;/*** 1.创建一个Runnable接口的实现类*/
public class Battle implements Runnable{private Hero h1;private Hero h2;public Battle(Hero h1, Hero h2){this.h1 = h1;this.h2 = h2;}/*** 2.在实现类中重写Runnable接口的run方法,设置线程任务*/public void run(){while(!h2.isDead()){h1.attackHero(h2);}}
}

 TestThread.java(测试类) 

package com.zhy.multiplethread;public class TestThread {public static void main(String[] args) {Hero hero1 = new Hero("米莱迪",350,60);Hero hero2 = new Hero("诸葛亮",300,50);Hero hero3 = new Hero("亚瑟",450,70);Hero hero4 = new Hero("猪八戒",400,60);//3.创建一个Runnable接口的实现类对象Battle battle1 = new Battle(hero1,hero2);Battle battle2 = new Battle(hero3,hero4);//4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象;调用Thread类中的start方法,开启新的线程执行run方法new Thread(battle1).start();new Thread(battle2).start();}
}

实现Runnable接口创建多线程程序的好处:

  1. 实现了Runnable接口,还可以继承其他的类,实现其他的接口;避免了单继承的局限性。
  2. 把设置线程任务和开启新线程进行了分离,增强了程序的扩展性,降低了程序的耦合性(解耦)。

1.4.3  使用匿名内部类

  • 匿名:没有名字。
  • 内部类:存在其他类内部的类。

格式:

        new 父类/接口(){
                重写父类/接口中的方法
        };

        

作用:简化代码

        

实现方式:

  1. 把(子类继承父类,重写父类的方法,创建子类对象)合一步完成。
  2. 把(实现类实现接口,重写接口中的方法,创建实现类对象)合成一步完成。
  3. 匿名内部类的最终产物:子类/实现类对象,而这个类没有名字。

代码示例: 

场景同上 

 TestThread.java(测试类) 

package com.zhy.multiplethread;public class TestThread {public static void main(String[] args) {Hero hero1 = new Hero("米莱迪",350,60);Hero hero2 = new Hero("诸葛亮",300,50);Hero hero3 = new Hero("亚瑟",450,70);Hero hero4 = new Hero("猪八戒",400,60);//匿名类:线程的父类是Threadnew Thread(){public void run(){while(!hero2.isDead()){hero1.attackHero(hero2);}}}.start();//匿名类:线程的接口是Runnablenew Thread(new Runnable() {@Overridepublic void run() {while(!hero4.isDead()){hero3.attackHero(hero4);}}}).start();}
}

1.5 Thread类

1.5.1 构造方法

  • Thread():分配一个新线程对象。
  • Thread(String name):分配一个指定名字的新线程对象。
  • Thread(Runnable target):分配一个带有指定目标的新线程对象。
  • Thread(Runnable target,String name):分配一个带有指定目标的新线程对象并指定名字。

1.5.2 常用方法 

  • String getName():获取当前线程的名称。
  • void start():启动当前线程,java虚拟机调用当前线程的run方法。
  • void run():当前线程要执行的任务在此处定义代码。
  • static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停。
  • static Thread currentThread():返回对当前正在执行的线程对象的引用。

1.5.3 Thread类中的常用方法练习

场景:模拟 秒针 的转动,每隔一秒执行依次。 

package com.zhy.thread;//继承自Thread类
public class ThreadTest extends Thread{//定义一个无参构造方法public ThreadTest(){}//定义一个有参构造方法public ThreadTest(String name){super(name);}//重写父类中的run方法@Overridepublic void run() {//获取当前正在执行的线程对象Thread thread = Thread.currentThread();//获取当前线程的名称String threadName = thread.getName();System.out.println(threadName);//也可以直接分成一步实现,采用链式编程System.out.println(Thread.currentThread().getName());}public static void main(String[] args) {//启动多线程1ThreadTest threadTest = new ThreadTest();threadTest.setName("xiaoQiang");threadTest.start();//启动多线程2new ThreadTest("wancai").start();//模拟秒针,每隔一秒执行一次for (int i = 1; i <= 60; i++){System.out.println(i);try {//该方法是一个编译时异常,必须处理Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}}}
}

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

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

相关文章

《QT实用小工具·二十四》各种数学和数据的坐标演示图

1、概述 源码放在文章末尾 该项目实现了各种数学和数据的坐标演示图&#xff0c;下面是demo演示&#xff1a; 项目部分代码如下&#xff1a; #ifndef FRMMAIN_H #define FRMMAIN_H#include <QWidget> class QAbstractButton;namespace Ui { class frmMain; }class fr…

吴恩达机器学习-异常检测(Anomaly Detection)

在本练习中&#xff0c;您将实现异常检测算法&#xff0c;并将其应用于检测网络上出现故障的服务器。 文章目录 1-包2-异常检测2.1问题陈述2.2数据集2.3高斯分布2.2.1高斯实现的估计参数&#xff1a;2.2.2选择阈值&#x1d716; 2.4高维数据集 1-包 首先&#xff0c;让我们运…

基于FPGA的以太网相关文章导航

首先需要了解以太网的一些接口协议标准&#xff0c;常见的MII、GMII、RGMII时序&#xff0c;便于后续开发。 【必读】从MII到RGMII&#xff0c;一文了解以太网PHY芯片不同传输接口信号时序&#xff01; 介绍一款比较老的以太网PHY芯片88E1518&#xff0c;具有RGMII接口&#xf…

代码随想录阅读笔记-二叉树【总结】

二叉树的理论基础 代码随想录 (programmercarl.com)&#xff1a;二叉树的种类、存储方式、遍历方式、定义方式 二叉树的遍历方式 深度优先遍历 代码随想录阅读笔记-二叉树【递归遍历】-CSDN博客&#xff1a;递归三部曲初次亮相代码随想录阅读笔记-二叉树【迭代遍历】-CSDN博…

thinkphp6入门(22)-- 如何下载文件

假设在public/uploads文件夹下有一个文件test.xlsx 在前端页面添加下载链接&#xff0c;用户点击该链接即可下载对应的文件。 <a href"xxxxxxx/downloadFile">下载文件</a> 2. 在后端控制器方法中&#xff0c;我们需要获取要下载的文件路径&#xff0…

java+saas模式医院云HIS系统源码Java+Spring+MySQL + MyCat融合BS版电子病历系统,支持电子病历四级

javasaas模式医院云HIS系统源码JavaSpringMySQL MyCat融合BS版电子病历系统&#xff0c;支持电子病历四级 云HIS系统是一款满足基层医院各类业务需要的健康云产品。该产品能帮助基层医院完成日常各类业务&#xff0c;提供病患预约挂号支持、病患问诊、电子病历、开药发药、会员…

C语言—用EaxyX绘制实时钟表

代码效果如图 #undef UNICODE #undef _UNICODE #include<graphics.h> #include<conio.h> #include<math.h>#define width 640 #define high 480 #define PI 3.14159int main() {initgraph(width, high);int center_x, center_y;center_x width / 2;center_y…

基于 SMM 汽车交易系统(源码+配套文档)

摘要 电子商务的兴起不仅仅是带来了更多的就业行业。同样也给我们的生活带来了丰富多彩的变化。多姿多彩的世界带来了美好的生活&#xff0c;行业的发展也是形形色色的离不开技术的发展。作为时代进步的发展方面&#xff0c;信息技术至始至终都是成就行业发展的重要秘密。不论…

nginx学习记录-负载均衡策略

1. 负载均衡基本策略配置 1.1 weight&#xff08;权重&#xff09;配置 weight表示当前服务器承载的业务比例。假设现在有两台服务器A和B组成集群&#xff0c;但是A和B的配置不一样&#xff0c;A的性能更好些&#xff0c;那么此时我们希望服务器A能承载更多的业务&#xff0c…

【Ubuntu】update-alternatives 命令详解

1、查看所有候选项 ​​​​​​​sudo update-alternatives --list java 2、​​​​​​​更换候选项 sudo update-alternatives --config java 3、自动选择优先级最高的作为默认项 sudo update-alternatives --auto java 4、删除候选项 sudo update-alternatives --rem…

halcon缺陷检测-印刷品检测(差异化模型),键盘字符缺陷检测

前言 在实际项目中&#xff0c;印刷品缺陷检测是缺陷检测中的难点项目。通常印刷品检测往往具备缺陷小&#xff0c;缺陷所在位置不固定&#xff0c;出现少印或者多印的情况。并且由于产线原因&#xff0c;大量的印刷品在视野中的大小并不是完全一致的&#xff0c;可能出现细微…

java-数组转换为List集合

方法一&#xff1a;使用 Arrays.asList() 方法 Arrays.asList() 方法可以将数组转换为一个固定大小的List。 import java.util.Arrays; import java.util.List; import java.util.ArrayList; public class ArrayToListExample { public static void main(String[] args…

易绘创云打印怎么样?易绘创云打印好用吗?

随着云技术的发展&#xff0c;云打印等概念也逐渐火热了起来。作为当下云打印服务行业中的佼佼者&#xff0c;易绘创云打印服务页一直被众多用户讨论着。那么易绘创云打印怎么样&#xff1f;易绘创云打印好用吗&#xff1f;今天小易就带大家来介绍一下。 易绘创云打印怎么样&am…

C语言面试题之合法二叉搜索树

合法二叉搜索树 实例要求 实现一个函数&#xff0c;检查一棵二叉树是否为二叉搜索树&#xff1b; 示例 1: 输入:2/ \1 3 输出: true 示例 2: 输入:5/ \1 4/ \3 6 输出: false 解释: 输入为: [5,1,4,null,null,3,6]。根节点的值为 5 &#xff0c;但是其右子节点值为 4 …

Vuex(vue 项目中实现 频繁、大范围数据共享的技术方案)

参考文档(点击查看) 好处 1.数据的存取一步到位&#xff0c;不需层层传递 2.数据的流动非常清晰 3.存储在Vuex中的数据都是响应式的&#xff08;数据更新后&#xff0c;使用数据的组件都会自动更新&#xff09; Vuex基础配置 npm i vuex3.6.2state中用来存储数据&#xff0c…

三:synchronized 关键字

目录 1、共享带来的问题2、synchronized 用法3、类加载器对 Class 锁的影响4、synchronized 实现原理4.1、同步方法、同步代码块4.2、对象内存布局4.3、Monitor 对象定义 5、synchronized 与原子性6、synchronized 与可见性7、synchronized 与有序性8、synchronized 锁升级8.1、…

外包干了15天,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四年的功能…

第十四届蓝桥杯大赛软件赛省赛C/C++大学 B 组

第十四届蓝桥杯大赛软件赛省赛C/C大学 B 组 文章目录 第十四届蓝桥杯大赛软件赛省赛C/C大学 B 组1、日期统计2、01串的熵3、冶炼金属4、飞机降落5、接龙数列6、岛屿个数7、子串简写8、整数删除9、景区导游10、砍树 1、日期统计 分析&#xff1a; 本题的意思就是2023年一整年&a…

c++作业day4

头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer> #include <QTime> #include <QTextToSpeech> #include <QMessageBox> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass…

技术分享 | Frida 实现 Hook 功能的强大能力

Frida 通过 C 语言将 QuickJS 注入到目标进程中&#xff0c;获取完整的内存操作权限&#xff0c;达到在程序运行时实时地插入额外代码和数据的目的。官方将调用代码封装为 python 库&#xff0c;当然你也可以直接通过其他的语言调用 Frida 中的 C 语言代码进行操作。 Frida安装…