多线程的创建方式及多线程应用场景

article/2024/11/15 6:14:40
  • 本篇大概详解思路如下思维导图:

目录

在java程序中创建线程

start()和run()的区别

start()方法为啥不能被重复调用

创建线程的7种方式

多线程提高速度

多线程的使用场景


在java程序中创建线程

我们知道一个进程包括多个线程(pcb---每个线程对应一块pcb,一个进程包括多个pcb),多个线程之间是并发执行的,其实当我们学第一个hello,world程序这个在运行的程序就是一个java进程

创建一个java进程会创建很多进程(与JVM相关的....),同时也会创建一个主线程 -- main线程(这与main方法不一样)

创建线程都与Thread类有关系,我们第一步就是创建它的实例

创建一个新线程

//自定义创建MyThread类 继承 Thread 类public static class MyThread extends Thread{@Overridepublic void run() {//为线程准备任务 --- 线程接下来要执行的任务//此时并没有创建线程System.out.println("我是Thread....");}}public static void main(String[] args) {Thread t = new MyThread();//创建 线程实例对象 t//创建线程 将新建状态NEW设置为就绪状态,等待CPU时间片//(系统安排一个时间调用Thread.run方法)来调用run方法t.start();System.out.println("我是main");}

 通过打印结果我们就可以发现打印结果的顺序与代码的执行顺序是不同的. 所以,CPU在进行调度时是以不确定的方式或者随机时间来执行run任务的.

再次理解并发编程

 随着执行程序,JVM就开启了一个java进程,创建main(主线程)开始执行,随后调用t.start(),同时新线程也被创建(这里任务不是立即执行而是设置就绪状态要等待系统让Thread来执行run任务),这里主线程和Thread线程之间是取决于操作系统的调度(我们可以简单理解为随机调度),最后两个线程任务执行完毕,最终整个进程就结束.

每个线程都是独立的执行流,两个执行流是并发执行的,执行顺序取决于操作系统的调度

start()和run()的区别

public static class MyThread extends Thread{@Overridepublic void run() {while(true){System.out.println("我是Thread!!!");try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {Thread t = new MyThread();t.start();//t.run();while(true){System.out.println("我是main!!!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
  • 从这个代码就会发现当你调用run方法时它并不会打印main而是一直打印Thread,这是因为并没有创建新的线程而只是调用了普通的方法run
  • 当调用start()方法时你会发现main和Thread交替打印,原因就是调用start()方法是创建一个新的线程,两个线程之间(主线程和Thread线程)之间是并发执行的
  • 调用start()方法才是真正的创建一个新的线程,而调用run()只是调用主程序的一个方法并没有创建新的线程
  • 因为一个线程只能被创建一次,所以start()方法不能被重复调用(如果重复调用会抛出异常),而run方法是一个普通的方法可以重复被调用
  • 调用start()方法不是立即被执行而是将新建状态设置为就绪状态,调用run方法是立即执行任务

start()方法为啥不能被重复调用

通过源码:

因为一个线程只能被创建一次,所以start()不能被重复调用,线程是不可逆的,当第一次调用start()方法时他会将新建状态NEW设置为就绪状态,当再次调用start()方法是就会抛出异常.


创建线程的7种方式

  • 通过自定义MyThread类来继承Thread类
public static class MyThread extends Thread{@Overridepublic void run() {//准备任务--这里只是要执行的任务准备好while(true){System.out.println("我是Thread!!!");try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {Thread t = new MyThread();//创建Thread实例tt.start();//真正的创建线程while(true){System.out.println("我是main!!!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
  • 实现Runnable接口
public static class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("我是Thread!!!");}}public static void main(String[] args) {Runnable r = new MyRunnable();//创建Runnable接口的实例Thread t = new Thread(r);//将Runnable接口对象传进Thread中t.start();System.out.println("我是main!!!");}

这里因为Thread类有一个构造方法就可以传Runnable接口对象 Thread(Runnable target)

 通过源码这里也可以看到Thread类实现了Runnable接口

  • 通过Thread匿名内部类的形式
public static void main(String[] args) {Thread t = new Thread(){@Overridepublic void run() {//准备任务System.out.println("我是Thread!!!");}};t.start();//创建线程System.out.println("我是main!!!");}
  • 通过Runnable匿名内部类的形式
 public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("我是Thread!!!!");}});t.start();System.out.println("我是main!!!");}
  • 通过lambda表达式(推荐做法)
public static void main(String[] args) {Thread t = new Thread(()->{System.out.println("我是Thread!!!");});t.start();System.out.println("我是main!!!");}

为啥使用线程???

我们知道创建一个进程首先创建一块pcb,然后为进程分配系统资源,最后将pcb加到双向链表中,因为这个位进程分配系统资源造成CPU速率下降,所以引出线程,线程只需要创建pcb,然后将pcb加到链表中,因为多个线程之间共享同一个进程的资源

单核CPU已经发挥到极致,要想速度更快就要充分利用CPU多核,就要进行并发编程--多个线程并发执行,又因为在某些场景下需要等待IO,为了让在等待IO时间内多做一些其他事情,就需要多个线程之间并发执行.

使用线程坏处???

当线程数过多是一个线程崩溃可能会导致整个进程崩溃,还有可能会导致线程安全问题,上下文切换,死锁问题.

多线程提高速度

我们来演示一下单个线程,和多个线程的速度比较

public static final long COUNT = 20_0000_0000;public static void serial(){long start = System.currentTimeMillis();long a = 0;for(int i =0;i<COUNT;++i){a++;}a = 0;for(int i =0;i<COUNT;++i){a++;}long end = System.currentTimeMillis();System.out.println("单线程所消耗的时间" + (end - start) + "ms");}public static void currency(){long start = System.currentTimeMillis();Thread t1 = new Thread(()->{;long a = 0;for(int i =0;i<COUNT;++i){a++;}});Thread t2 = new Thread(()->{long a = 0;for(int i =0;i<COUNT;++i){a++;}});t1.start();t2.start();try {t1.join();//等待t1线程结束任务在执行下一个t2.join();//等待t2线程结束任务在执行,如果没有任务就返回/退出} catch (InterruptedException e) {e.printStackTrace();}long end = System.currentTimeMillis();System.out.println("多线程所消耗的时间" + (end - start) + "ms");}public static void main(String[] args) {serial();currency();}

通过代码演示多个线程之间执行比单个线程之间执行速度快一些,但是并没有精准的两个线程之间就等一2*一个线程的速度,因为会有一些会有调度以及创建自身线程的开销.

多线程的使用场景

1.CPU密集型场景

使用多线程,可以充分利用CPU多核资源,提高效率

2.IO密集型场景

由于IO操作不消耗CPU就能快速完成读写操作,在这段等待IO(读写硬盘,读写网卡...)操作的时间,使用多线程让CPU能够做一些其他的工作


http://chatgpt.dhexx.cn/article/WVCgUT0a.shtml

相关文章

Java多线程的应用场景和应用目的举例

微信公众号&#xff1a;javafirst 01 通俗的解释一下多线程 多线程用于堆积处理&#xff0c;就像一个大土堆&#xff0c;一个推土机很慢&#xff0c;那么10个推土机一起来处理&#xff0c;当然速度就快了&#xff0c;不过由于位置的限制&#xff0c;如果20个推土机&#xff0…

多线程的使用场景

多线程的使用 使用线程池ExecutorService &#xff0c;exe.execute来开始线程&#xff0c;thread,runabble,callabble都可以&#xff0c;isTerminated来判断线程池的线程是否都执行完毕 Testpublic void testThread() throws InterruptedException {//创建线程池ExecutorServi…

【多线程/线程池】项目中实际应用场景

场景一、快速响应用户的请求 描述: 用户发起的实时请求&#xff0c;服务追求响应时间。比如说用户要查看一个商品的信息&#xff0c;那么我们需要将商品维度的一系列信息如商品的价格、优惠、库存、图片等等聚合起来&#xff0c;展示给用户。 场景二、快速处理批量的任务 描…

多线程相关实例(多线程经典应用场景)

转载&#xff0c;from 网络&#xff0c;未能找到原创人员&#xff0c;只找到一个转载 https://blog.csdn.net/u013521220/article/details/79648270 多线程实例目录 相关知识&#xff1a;经典案例一&#xff1a;三个售票窗口共同出售20张票经典案例二&#xff1a;AB两人共用一个…

多线程的实现和使用场景

多线程的实现和使用场景 一、多线程实现方式1.1 Thread实现1.2 Runnable实现 二、多线程的使用场景1.多线程使用场景1.1 多线程应该最多的场景&#xff1a;1.2多线程的常见应用场景&#xff1a; 2.多线程小案列2.1 多线程计算2.2 多线程实现卖票小程序2.3多线程卖票小程序优化2…

子网掩码、网关及网络号与主机号的区分与计算

前言&#xff1a; 当前使用的IP地址有4个字节&#xff08;32bit&#xff09;组成&#xff0c;即IPV4编码方式。每个IP地址包括两部分&#xff1a;网络号和主机号。当分配给主机号的二进制位越多&#xff0c;则能标识的主机数就越多&#xff0c;相应地能标识的网络数就越少&…

计算机网络之ip、子网掩码、网络号、主机号等概念解析

在工作中谈论到计算机网络时&#xff0c;有几个经常出现的术语&#xff0c;比如&#xff1a;ip、子网掩码、网段等等。之前对这些概念的理解都比较模糊&#xff0c;只知其大概意思&#xff0c;随着工作中遇到的网络问题越来越多&#xff0c;有必要详细理解一下计算机网络的基础…

IP地址、子网掩码、网络号、主机号、网络地址、主机地址以及ip段/数字-如192.168.0.1/24是什么意思?

背景知识 IP地址 IP地址被用来给Internet上的电脑一个编号。大家日常见到的情况是每台联网的PC上都需要有IP地址&#xff0c;才能正常通信。我们可以把“个人电脑”比作“一台电话”&#xff0c;那么“IP地址”就相当于“电话号码”&#xff0c;而Internet中的路由器&#xff0…

若尔当型状态空间方程的能控能观判断

若尔当型状态空间方程的能控能观判断 对于若尔当型状态空间方程&#xff1a; 能控充要条件&#xff1a;当且仅当同一特征值对应的每个若尔当块的最后一行对应B矩阵的行向量线性无关。 注:每个特征值均应满足以上条件。 能观充要条件&#xff1a;当且仅当同一特征值对应的每个…

状态空间方程的能控性与能观性判断

状态空间方程的能控性与能观性判断 能控性判断方法 对于状态空间方程&#xff0c;判断是否能控。 注&#xff1a;由于输出在能控性方面不起任何作用&#xff0c;因此在能控性研究中忽略输出方程。 矩阵对任意t>0均非奇异。的“能控性矩阵”行满秩。的矩阵在A的任一特征值…

Matlab:传递函数(含迟延环节)/状态空间方程/z传递函数的构造/运算/转化

1、传递函数 1.1 构造传递函数 &#xff08;1&#xff09; Matlab可以这样构造上式 num[10 30 20]; den[1 12 47 60]; sysctf(num,den) 运行结果 &#xff08;2&#xff09; 根据零极点构造表达式&#xff1a; z[-1 -2]; p[-3 -4 -5]; k10; sysczpk(z,p,k) 运行结果&…

【电机/鼠笼型感应电机】IM模型建立、坐标变换、状态空间方程推导

目录 一、感应电机三相数学模型 1.1 磁链方程 1.2 电压方程 1.3 转矩方程和运动方程 二、坐标变换 2.1 原理 2.2 Clarke变换和逆变换 2.3 Park变换和逆变换 三、感应电机两相数学模型 . 3.1 αβ坐标系中 3.2 dq坐标系中 四、感应电机状态方程 4.1 状态变量的选择 …

c语言 状态空间控制方程,MPC学习笔记1:基于状态空间模型的预测控制(2)

基于估计的无约束预测控制 1.引言 基本上这两个部分都是在线性理论的框架下,利用状态空间法来建模、求解控制律。状态空间模型在理论分析上具有很强的优越性,但实际应用中能直接准确且经济地获取系统状态并不容易。有些状态,尤其是温度(如火箭喷口温度等)只能间接估计,因此…

控制建模matlab练习02:状态空间方程系统

此建模从一个简单的系统&#xff1a;弹簧质量阻尼系统&#xff0c;来学习状态空间方程系统。 m是质量&#xff1b;b是阻尼系数&#xff1b;k是弹簧系数。 此系统的状态空间方程&#xff0c;如下图&#xff1a; 01新建脚本&#xff08;.m文件&#xff09; 我们在matlab主页&a…

卡尔曼滤波(Kalman Filtering)——(3)数据融合 状态空间方程

数据融合 协方差 状态空间方程 观测器 一、数据融合假设举例公式推导过程再次理解 二、状态空间方程阻尼滑块模型1、连续表达式2、离散表达形式3、符号含义 参考文献 一、数据融合 假设举例 假设测量一物体的质量&#xff0c;现在有两个测量设备但是都存在误差且误差服从正态分…

[现代控制理论]2_state-space状态空间方程

[现代控制理论]11_现代控制理论串讲_完结_pdf获取 [现代控制理论]10_可观测性与分离原理_观测器与控制器 [现代控制理论]9_状态观测器设计_龙伯格观测器 [现代控制理论]8.5_线性控制器设计_轨迹跟踪simulink [现代控制理论]8_LQR控制器_simulink [现代控制理论]7_线性控制器设计…

现代控制理论(一) 状态空间方程

文章目录 状态方程和输出方程基本的状态空间方程 线性非线性时变时不变系统的能控能观状态方程的解无输入线性时不变转移矩阵拉普拉斯求转移矩阵 有输入线性时不变 控制什么&#xff1f; 输入u1,u2,u3,…输出y1,y2,y3…的系统。u是控制量&#xff0c;y是响应结果&#xff0c;也…

【离散系统】传递函数和状态空间方程离散化

本文如有错误&#xff0c;恳请指正。 目录 离散系统 采样控制系统 数字控制系统 信号采样 采样定理&#xff08;香农定理&#xff09; 信号保持—零阶保持器 Z变换 Z 变换方法 级数求和法 部分分式法 基本定理 Z反变换 Z反变换方法 长除法 部分分式法&#xff0…

matlab 状态空间的波特图,MATLAB:对于状态空间方程的系统辨识

本文介绍了如何利用MATLAB辨识状态空间方程中的未知参数。 假设我们的被控系统的表达如下: 我们想要通过实验数据辨识出参数K1和K2​,方法如下: 第一步,采集实验数据。 需要的数据包括系统一段时间内的系统输出Y(ts),以及控制量U(ts),这些数据应该是以某个固定的采样频率…