【JavaEE】_线程与多线程的创建

目录

1. 线程的概念

2. 创建与使用多线程

2.1 方式1:继承Thread类

2.2 方式2: 实现Runnable接口

2.3 以上两种创建线程方式的对比

3. 多线程的优势-增加运行速度


1. 线程的概念

进程的存在是由于系统的多任务执行需求,这也要求程序员进行并发编程;

使用多进程是完全可以实现并发编程的,但如果要频繁地创建或销毁(如分配、销毁内存或文件)以及频繁地调度进程,资源的申请和释放不仅低效,成本也非常高;

为了解决这个问题,通常会通过两个方式:

(1)进程池:效率有一定提高,但进程池中的闲置进程不使用的时候仍然在消耗系统资源,故而使用进程池的系统资源消耗是非常大的;

(2)线程:线程比进程更轻量,每个线程也能够执行一个任务(代码),也能够并发编程;

创建、调度、销毁一个线程的成本相比进程而言要低很多,在Linux上也把线程称为轻量级进程,

进程重量重在资源的申请和释放,线程则是包含在进程中的,一个进程中的多个线程共用同一份资源(同一份内存+文件),只有在创建进程的第一个线程时,由于需要分配资源,成本是相对较高对的,后续在这个进程中再创建其他线程的成本都比较低

但是并非线程越多越好,如果线程过多,就会存在资源竞争导致速度受限;

注:进程与线程的区别与联系?

(1)进程包含线程,一个进程里可以包含一个线程,也可以包含多个线程;

(2)进程和线程都是为了处理并发编程场景,但进程频繁创建、调度、释放时效率较低,消耗较大;而线程由于少了申请释放资源的过程,故而更轻量,创建、调度、释放都效率更高,消耗更少

(3)操作系统创建进程需要给进程分配资源,故而进程是操作系统分配资源的基本单位

操作系统创建线程是要在CPU上调度执行,故而线程是操作系统调度执行的基本单位

(4)进程具有独立性,每个进程都由各自的虚拟地址空间,进程之间互不影响;

同一个进程中的多个线程共用同一个内存空间,线程之间可能会互相影响;

2. 创建与使用多线程

2.1 方式1:继承Thread类

java标准库提供了一个Thread类来表示、操作线程,Thread类也可视为是java标准库提供的API;

创建好的Thread实例和操作系统中的线程是一一对应的关系;

操作系统提供了一组关于API(C语言),java对于这组API进一步封装形成了Thread类;

示例代码1:单线程创建示例

class MyThread extends Thread{@Overridepublic void run(){System.out.println("Hello Thread.");}
}
public class Demo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();}
}

注:(1)通过Thread类创建线程有很多种写法,最简单的就是创建子类继承Thread并且重写run方法;

(2)run方法中描述该线程要执行哪些代码,由于每个线程都是并发执行的,因此需要告知每个线程要执行的代码内容,run方法中的逻辑是在新创建出的线程中被执行的代码;

(3)start方法的调用代表着在系统中真正创建了线程,此时才开始执行上文的run操作;

(4)这里创建线程是在同一个进程中创建的;

(5)线程之间是并发进行的:

(6)线程强制中断异常是多线程中最常遇到的异常之一:

(7)Thread是java.lang中的类,是不需要导入包的,类似的还有String也是不需要导入的;

 示例代码2:多线程创建示例

class MyThread extends Thread{@Overridepublic void run(){while(true){System.out.println("Hello Thread");try {Thread.sleep(1000);//休眠:强制使线程进入阻塞状态  单位为ms//即1s内这个线程不会到cpu上执行}catch(InterruptedException e){e.printStackTrace();}}}
}
public class Demo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();while(true){System.out.println("Hello Main");try {Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}}
}

截取部分输出结果如下:

注:(1)一个进程中至少会有一个线程,在一个java进程中也至少会有一个调用main方法的线程,只是该线程是系统自动生成的而非手动创建的,此时我们手动创建的t线程与自动创建的main线程就是并发执行的关系,这两个线程从宏观上看该输出结果就是同时执行的;

(2)两个线程都是打印一条语句后休眠1s,当1s结束后,系统先唤醒哪个线程是随机的,即对于操作系统来说,内部对线程之间的调度顺序在宏观上也可以认为是随机的,这种调度方式也称为抢占式执行;

(3)sleep是一个毫秒级休眠语句,并没有那么精确,比如sleep(1000)的含义是1000ms之内不能上CPU,而不是1000ms之后准时上CPU,故而结束阻塞状态的具体时间是不确定的,这与线程之间的调度是随机的也是彼此互相印证的;

(4)start方法用于启动线程;

示例代码3:使用匿名内部类

public class Demo3 {public static void main(String[] args) {//1.创建一个匿名内部类继承自Thread类//2.重写run方法//3.new这个匿名内部类的实例Thread t = new Thread(){public void run(){System.out.println("Hello Thread.");}};t.start();}
}

2.2 方式2: 实现Runnable接口

创建一个类实现Runnable接口,再创建Runnable实例传给Thread实例;

代码示例1:实现Runnable接口创建线程

//Runnable 就是在描述一个任务
class MyRunnable implements Runnable{@Overridepublic void run(){System.out.println("Hello");}
}
public class Demo2 {public static void main(String[] args) {Thread t = new Thread(new MyRunnable());t.start();}
}

通过Runnable来描述任务的内容,进一步地再把描述好的任务交给Thread实例;

代码示例2:使用匿名内部类

public class Demo4 {public static void main(String[] args) {//1.new Runnable的匿名内部类//2.将new的Runnable实例传给Thread的构造方法Thread t = new Thread(new Runnable(){public void run(){System.out.println("Hello Thread.");}});t.start();}
}

需要将new 的Runnable的实例传递给Thread,故而需要包含其重写的run方法;

代码示例3:使用lambda表达式

public class Demo5 {public static void main(String[] args) {Thread t = new Thread(()->{System.out.println("Hello Thread.");});t.start();}
}

lambda表达式就是一个匿名方法,()表示方法参数,->表示是一个lambda,{}中编写方法内容;

2.3 以上两种创建线程方式的对比

通常认为Runnable方式会更好一点,能够做到让线程与线程执行的任务更好地进行解耦;

编写代码通常希望高内聚、低耦合。

Runnable只是描述了一个任务,但是任务的执行方式是进程、线程、线程池还是协程来执行,Runnable内部并不作涉及,Runnable内部的代码也不涉及;

3. 多线程的优势-增加运行速度

多线程编程的优势显著体现在可以提高任务完成的效率:

如现有两个整数变量,分别对这两个变量自增10亿次,分别使用一个线程与两个线程进行演示:

public class Demo6 {private static final long count = 10_0000_0000;public static void serial(){  //串型执行//记录程序执行时间long beg = System.currentTimeMillis();long a = 0;for(long i=0;i<count;i++){a++;}long b = 0;for(long i=0;i<count;i++){b++;}long end = System.currentTimeMillis();System.out.println("Single Thread Time: "+(end-beg)+" ms.");}public static void concurrency() throws InterruptedException {long beg = System.currentTimeMillis();Thread t1 = new Thread(()->{long a = 0;for(int i=0;i<count;i++){a++;}});t1.start();Thread t2 = new Thread(()->{long b = 0;for(int i=0;i<count;i++){b++;}});t2.start();//不能在此处直接记录结束时间,该方法是在main线程中执行的;//main线程与t1、t2线程是并发执行的,即t1、t2尚未执行结束此时就已经记录结束时间了//应将main线程等待t1与t2线程执行完毕再进行计时t1.join();t2.join();//join方法效果就是等待线程结束,哪个线程调用则令main线程等待哪个线程结束long end = System.currentTimeMillis();System.out.println("Multi Thread Time: "+(end-beg)+" ms.");}public static void main(String[] args) throws InterruptedException {serial();concurrency();}
}

输出结果为:

注:(1)增加线程并非一定会达到翻倍的速度提升,因为两个线程在底层到底是并行执行还是并发执行并不确定, 底层微观真正并行执行的时候,效率才会有显著提升;

(2)当count不够大时,反而可能会导致程序执行速度更慢,因为创建线程本身也需要时间开销,此时代码的执行时间反而更多地消耗在了创建线程上;

(3)多线程适合应用于CPU密集型的程序,当程序需要进行大量的计算时,使用多线程就可以更充分地利用CPU的多核资源;

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

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

相关文章

LabVIEW卫星电视接收仿真系统

LabVIEW卫星电视接收仿真系统 随着卫星电视数字化的加速&#xff0c;传统模拟信号接收系统已无法满足需求。设计一套船载数字卫星电视接收系统&#xff0c;通过LabVIEW环境进行仿真实验&#xff0c;验证系统设计的可行性与有效性&#xff0c;满足数字信号接收的高精度要求&…

嵌入式Qt Qt中的信号处理

一.Qt中的信号处理 Qt消息模型&#xff1a; - Qt封装了具体操作系统的消息机制 - Qt遵循经典的GUI消息驱动事件模型 Qt中定义了与系统消息相关的概念; Qt中的消息处理机制&#xff1a; Qt的核心 QObject::cinnect函数&#xff1a; Qt中的“新”关键字&#xff1a; 实验1 初探…

Rust 基本环境安装

rust 基本介绍请看上一篇文章&#xff1a;rust 介绍 rustup 介绍 rustup 是 Rust 语言的安装器和版本管理工具。通过 rustup&#xff0c;可以轻松地安装 Rust 编译器&#xff08;rustc&#xff09;、标准库和文档。它也允许你切换不同的 Rust 版本或目标平台&#xff0c;以及…

petalinux安装的问题:

1. 安装是成功的&#xff0c;但是安装位置&#xff0c;就是用来存放petalinux的文件夹里没有文件 我是照着正点的文档安装的&#xff0c;出现的一个问题就是最后执行文件这里&#xff1a; -d 后面这个文件夹的路径&#xff0c;我看网上的教程也都是跟文档一致的 /opt/pkg/peta…

每日五道java面试题之java基础篇(十一)

目录: 第一题. Java死锁如何避免&#xff1f;第二题. 为什么⽤线程池&#xff1f;解释下线程池参数&#xff1f;第三题. 线程池的底层⼯作原理第四题. ReentrantLock中tryLock()和lock()⽅法的区别第五题. Sychronized和ReentrantLock的区别? 第一题. Java死锁如何避免&#x…

社区养老|社区养老服务系统|基于springboot社区养老服务系统设计与实现(源码+数据库+文档)

社区养老服务系统目录 目录 基于springboot社区养老服务系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员部分功能 &#xff08;1&#xff09; 用户管理 &#xff08;2&#xff09;服务种类管理 &#xff08;3&#xff09;社区服务管理 &#xff08…

【教学类-19-08】20240214《ABAB式-规律黏贴18格-手工纸15*15CM-一页3种图案,A空,纵向、无边框》(中班)

背景需求 利用15*15CM手工纸制作AB色块手环&#xff08;手工纸自带色彩&#xff09;&#xff0c;一页3个图案&#xff0c;2条为一组&#xff0c;黏贴成一个手环 素材准备 代码展示 # # 作者&#xff1a;阿夏 # 时间&#xff1a;2024年2月14日 # 名称&#xff1a;正方形数字卡…

2023 车载摄像头产业链梳理

1. 车载摄像头的发展和市场空间 车载摄像头&#xff0c;最早在车载行车记录仪、倒车影像功能中被应用。而随着汽车产业步入智能化&#xff0c; 360 环 视 、 ADAS 、 智 能 座 舱 等 应 用 为 车 载 摄 像 头 带 来 了 巨 大 的 市 场 需 求 。 特 别 是 在 自 动 驾驶 、 36…

BBC英式口语~发音练习~笔记整理

参考资料 原视频地址&#xff1a; https://www.bilibili.com/video/BV1D7411n7bS/?spm_id_from333.1245.0.0&vd_source5986fc7c8e6d754f3ca44233573aeaff 笔记图片

MySQL篇之覆盖索引

一、定义 覆盖索引是指查询使用了索引&#xff0c;并且需要返回的列&#xff0c;在该索引中已经全部能够找到。 二、例子 1. id为主键&#xff0c;默认是主键索引。 2. name字段为普通索引。 select * from tb_user where id 1 覆盖索引 select id&#xff0c;na…

如何选择适合的社区店项目,开启创业之路

对于想要创业的人来说&#xff0c;选择一个适合的社区店项目是成功的关键。在这篇文章中&#xff0c;我将以一名资深鲜奶吧创业者的身份&#xff0c;分享一些关于如何选择适合的社区店项目的经验和见解&#xff0c;希望能给大家提供有价值的参考。 一、市场调研 在选择社区店…

海量数据处理商用短链接生成器平台 - 4

第六章 架构核心技术-池化思想-异步结合 性能优化最佳实践 第1集 RestTemplate里面的存在的问题你知道多少- Broken pipe错误 项目就更新到第六章了&#xff0c;剩下的内容 放百度网盘里面了&#xff0c;需要的来取。 链接&#xff1a;https://pan.baidu.com/s/19LHPw36dsxPB7…

四、JMS规范

JMS规范 一、JMS是什么二、MQ中间件对比三、JMS组成1.JMS Provider2.JMS Producer3.JMS Consumer4.JSM Message4.1 消息头4.2 消息体4.2.1 生产者4.2.2 消费者 4.3 消息属性 四、JMS可靠性1.PERSISTENT - 持久化1.1 参数设置1.2 Queue持久化1.3 Topic持久化1.3.1 持久的发布主题…

Linux文件操作类命令 touch | stat | cp | scp | alias | mv | dd | cat | head | tail

touch 1.创建空文件&#xff08;只有元数据信息&#xff0c;没有数据段内容&#xff09;touch 1.txt 2.对创建或已经存在的文件改变元数据信息的时间记录值-d 改变创建时间touch -d 20240101 1.txt -a改变访问时间 -m改变修改时间stat 查看元数据信息 Blocks是512字…

排序算法---桶排序

原创不易&#xff0c;转载请注明出处。欢迎点赞收藏~ 桶排序&#xff08;Bucket Sort&#xff09;是一种排序算法&#xff0c;它将待排序的数据分到几个有序的桶中&#xff0c;每个桶再分别进行排序&#xff0c;最后将各个桶中的数据按照顺序依次取出&#xff0c;即可得到有序序…

【机器学习笔记】 9 集成学习

集成学习方法概述 Bagging 从训练集中进行子抽样组成每个基模型所需要的子训练集&#xff0c;对所有基模型预测的结果进行综合产生最终的预测结果&#xff1a; 假设一个班级每个人的成绩都不太好&#xff0c;每个人单独做的考卷分数都不高&#xff0c;但每个人都把自己会做的…

在 Android 上部署自定义 YOLOv8 教程

在本教程中&#xff0c;我将向您展示如何在 Android 设备上使用自定义数据集部署 YOLOv8。想要了解如何在 Android 设备上使用您自己的数据集部署 YOLOv8&#xff1f;本文将展示如何操作。 Android 上的 自定义 YOLOv8 &#x1f525; ⚡️ 结果显示标题 对从 GoPro 流式传输到移…

Sora时代,我们的AI应该何去何从?——关于Sora大模型的思考

Sora时代&#xff0c;我们的AI应该何去何从?——关于Sora大模型的思考 一、Sora大模型&#xff1a;横空出世&#xff0c;让AI生成所有领域瑟瑟发抖二、Sora的出现代表了相关行业的灭亡&#xff1f;三、我们将何去何从&#xff1f; 一、Sora大模型&#xff1a;横空出世&#xf…

1.8 NLP自然语言处理

NLP自然语言处理 更多内容&#xff0c;请关注&#xff1a; github&#xff1a;https://github.com/gotonote/Autopilot-Notes.git 一、简介 seq2seq(Sequence to Sequence)是一种输入不定长序列&#xff0c;产生不定长序列的模型&#xff0c;典型的处理任务是机器翻译&#…

前端常见的设计模式

说到设计模式&#xff0c;大家想到的就是六大原则&#xff0c;23种模式。这么多模式&#xff0c;并非都要记住&#xff0c;但作为前端开发&#xff0c;对于前端出现率高的设计模式还是有必要了解并掌握的&#xff0c;浅浅掌握9种模式后&#xff0c;整理了这份文章。 六大原则&…