(java)进程和线程的联系和区别 。Java如何进行多线程编程?Thread 类及常见方法。

news2024/11/25 13:24:35

目录

进程 

1.进程具有独立性

————  虚拟地址空间

线程

 为什么要引入多个线程?

 多线程注意点

⁜⁜总结:线程和进程的区别和联系⁜⁜ (经典面试题)

Java如何进行多线程编程?

创建线程 

——方法1 继承 Thread 类

——方法2 实现 Runnable 接口

—— 使用Runnable的写法 和 直接继承 Thread 有什么区别?

匿名内部类 方法 

继承 Thread,重写run,但是使用匿名内部类 

实现Runnable,重写run,使用匿名内部类

基于 lambda 表达式 【推荐 比前面的方法都简单】

—— lambda 表达式 (介绍了回调函数)

 Thread 类的其他常见使用方法

—— Thread 的常见构造方法

—— Thread 的几个常见属性

 启动线程-start() (含经典面试题,start 和 run的区别)

中断线程 

-- 方案一 

--  方案二

线程等待 


进程 

1.进程具有独立性

首先介绍一下

————  虚拟地址空间

在这之前还要了解一下 —— “物理内存”

在早期的操作系统中,程序运行时分配的内存,就是 “物理内存”。

这个物理内存简单理解,就可以看成是一个宿舍楼,宿舍楼里有很多房间,每个房间占一个字节,且每个房间都有编号,这个编号就是“内存地址”。

那现在分配内存就直接从物理内存上分配,但是这时候就会出现问题

而操作系统需要给进程提供一个稳定的运行环境 ,上述的肯定不行。

所以操作系统就引入了 “ 虚拟地址空间 ” 的概念,  不直接分配物理内存了,而是分配一块虚拟的内存空间。操作系统对于内存又进行了一层抽象,如下图。

正是这样的机制,才带来了进程的独立性 。

进程是 资源分配 的基本单位。

(一个系统中可以有很多的进程,每个进程,都有自己的资源)

线程

在Java这样的生态中,不是很鼓励 多进程编程,更鼓励使用 多线程编程 

 为什么要引入多个线程?

为了实现 并发编程  ———— 当前的时代是一个 多核CPU的时代。

虽然多程 实现 并发编程,也是很不错的,但是,多程编程模式 太重了,效率不高,不管是创建,销毁,还是调度一个进程,消耗时间都比较多, 

总的来说,就是多进程 开销比较大,效率比较低。 (进程的开销主要是消耗在了申请资源上,进程是资源分配的基本单位

为了解决上述问题,我们就引入了 “线程(Thread)”。(也叫 “轻量级进程”)

创建,销毁,还是调度一个线程,都比进程要快。

但是线程是不能独立存在的,他必须依附于线程,进程包含线程 。

进程可以包含一个或多个线程。 也就是说,一个进程,最开始至少要包含一个线程,这个线程负责完成 执行代码的工作,也可以根据需要 创建更多的线程,来实现 "并发编程" 的效果。

每个线程都可以独立执行一些代码。 

实际情况,一个进程里有多个线程,而每个线程 ,都是可以独立进行调度的 ,每个线程也都有状态,优先级,上下文,记账信息......

一个进程可能使用一个PCB 或 多个PCB表示,每个PCB 对应到一个线程

上述结构决定了线程的特点

  1. 每个线程都可以 独立 在CPU上调度执行
  2. 同一个进程里的多个线程,共用同一份 内存空间 和 文件资源

所以创建线程的时候 不需要重新 申请资源 ,直接 复用 之前已经给 进程 分配好的资源。

这样就省去了 资源分配的开销,于是创建效率就高了。

画图捋一遍

得出 线程 是 调度执行 的基本单位。 

(一个进程中,可以有很多的线程,每一个 线程 都能 独立调度执行,共享 内存/硬盘 资源)

上述对于 多进程 多线程 的描述还是比较抽象的,那举一个生活上的例子 。

假如,就是现在有个院子,院子里有条生产线,现在产品销量比较好,老板想扩大一下规模,想多搞一条生产线,那现在就是有两个方案。  

方案一: 

在搞一个院子,那就有两条生产线了,但是再找一个院子,成本比较高。

方案二 :

 

在同一个院子里再搞一条生产线,是独立的,各自都能生产,但是这两个生产线共用一个院子,一组工人,一套物流体系,这样就节约了成本 还 提高了生产力 (资本家呀~)

方案一就使用了 多进程的方式 方案二就使用了 多线程的方式。

 多线程注意点

  1. 当到了一定程度时,再进一步增加线程数目时,效率无法进一步提升,反而会因为要调度     的线程数目太多,时调度的开销更大,反而会降低了效率。
  2. 当线程数目多了,可能就会产生一定的冲突,称为 "线程不安全问题" 。
  3. 如果一个线程抛出异常,没有被妥善处理(catch),就容易把整个进程都搞崩溃,那其他线程也就都没了。

⁜⁜总结:线程和进程的区别和联系⁜⁜ (经典面试题)

  1. 进程 可以包含一个或多个 线程
  2. 进程和线程都是用来实现 “并发编程” 场景的,但是线程比进程更轻量,更高效
  3. 在同一个进程里的线程,共用同一份资源(内存 和 硬盘),省去了申请资源的开销
  4. 进程具有独立性,一个进程挂了,不会影响到其他进程;同一个 进程 里的 线程,是可能会相互影响的 (线程安全问题 + 线程出现异常)
  5. 进程是资源分配的基本单位,线程是调度执行的基本单位。

Java如何进行多线程编程?

在java中使用线程,一般有下面几步

  • 创建线程
  • 启动线程
  • 中断线程
  • 线程等待 

创建线程 

线程是操作系统的概念。操作系统提供了一些API(应用程序接口),可以操作线程。

Java就利用 (线程)Thread类 针对上述系统API进行了进一步的抽象和封装(为了跨平台) 这样程序员只需要掌握这一套API就可以了。 

那java是如何创建线程的呢,接下来介绍

——方法1 继承 Thread 类

Thread类是Java标准库内置的类,在 java.lang 这个包下。

使用Thread类,创建 Thread对象,进一步就可以操作 系统内部的 线程了。 

继承 Thread 来创建一个线程类 (重写run),创建 MyThread 类的实例,,调用 start 方法启动线程

前面介绍了每个线程都是一个独立的执行流,每个线程都可以执行一系列的逻辑(代码),

那一个线程跑起来,该从那个代码开始执行呢?从入口方法(run方法)开始执行。

运行一个java程序,就跑起来一个java进程,而一个进程里至少有一个线程——主线程,主线程的入口方法就是 main方法 。

但是其他线程此时还只是一个”定义”,要想执行,还要“调用”,在主线程里调用。 具体该如何调用,如下:

 

⁜为什么我们上面的是run方法,但是这里调用的却是 start方法呢?

  • start 和 run 都是 Thread 的成员
  • 但是 run 只是描述了线程的入口(线程要做什么任务)
  • 而 start 才是真正调用了系统 API(应用程序接口),在系统中创建出线程,让线程再调用 run。

此上我们完成了第一个多线程,main方法对应了主线程,run方法对应了thread线程。

之后我们再稍稍复杂一下代码 ,死循环一下

可以看到这两个循环在 “同时执行 ”,两边的语句在交替打印。 

这就非常符合线程的特点 —— 每个线程都是独立执行的逻辑(都是独立的执行流) 。

程序走到 thread.start() 那里之后,兵分两路,一路继续走主线程,另一路走我们创建的新线程 

那这种执行方式就是我们前面所说的 “并发执行”,从而也就达到了 并发编程 的效果。充分的使用了多核CPU资源。

那如果我们把thread.start(), 改成thread.run() 会怎么样呢?

那此时,代码就不会创建出新的线程,只有一个主线程,那主线程只能依次执行,这个走完才能到下一步,那run()方法那里是死循环,那就有了下面的情况

  

只有hello thread 没有 hello main 

ps: 如果你想要打印的慢点,就可以利用 sleep(),(还得抛出个异常)

从上图我们可以看到,两条语句的执行顺序是不一定的,这个过程可以看成是 “随机的”

也就是说,操作系统,对于多线程的调度执行顺序,是“随机的” (这个随机和数学里的 概率均等的随机不一样,这个“随机”取决于 操作系统 对于线程调度的模块(调度器)的具体实现)

——方法2 实现 Runnable 接口

 实现 Runnable 接口,重写run(),创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为参数,调用 start 方法

从上面的代码可以看出,和继承Thread 的写法是一样的,作用也是描述线程的入口。 

从上图看出 这个 Runnable还是要搭配 Thread 使用

Runnable本身与线程没有直接的联系,这里的Runnable 单纯的表示 “可以运行的任务”,这个任务交给线程还是其他的什么来执行,Runnable并不关心。

把这个任务放到线程里来执行,最终还是要通过thread.start(), 这个操作,调用系统的API(应用程序接口)来完成创建线程的工作。

执行情况和上边一样 

—— 使用Runnable的写法 和 直接继承 Thread 有什么区别?

三个字概况:解耦合

(ps:耦合,相互影响越大,耦合越高)

👈(⌒▽⌒)👉 解释  👈(⌒▽⌒)👉

我们要知道,创建一个线程,需要两个关键操作:

  1. 明确线程要执行的任务

—— 任务本身不一定和线程相关,这个任务只是单纯执行一段代码不管它是使用单个线程还是多个线程去执行,或者什么其他的方法,都没什么区别,此时就可以把这个任务单独 提取出来,让任务和线程解耦合,那就可以随时把代码改成其他方式来执行这个任务

    2.调出系统API(应用程序接口)创建出线程

匿名内部类 方法 

继承 Thread,重写run,但是使用匿名内部类 

 

具体如何写,如下: 

其实没什么区别,就是把方法挪了个位置。和方法一本质一样,就是换了个写法。 

实现Runnable,重写run,使用匿名内部类

一样一样 

或者更简便 

基于 lambda 表达式 【推荐 比前面的方法都简单】

lambda表达式 是一种更简化的语法表示方式。(“语法糖” )。

相当于是 “匿名内部类” 的替换写法。

—— lambda 表达式 (介绍了回调函数)

 

 lambda 表达式 ,本质上是一个匿名函数(一次性的), 主要用来实现“回调函数”的效果。

(java中不允许函数独立存在,(Java这里叫方法),所以lambda 本质是函数式接口(还是没脱离类))

 ——“回调函数”是计算机中非常重要的术语,我们来了解一下

  • 首先我们要知道 “函数指针”

       函数指针指向内存空间的,函数为什么跑到内存里了?,这背后是操作系统 加载一个可执行程序 创建进程的过程 

       我们写的代码的都是一个一个文件,都在硬盘里,然后编译,得到个.exe, 还是个文件,当双击这个.exe, 操作系统会加载这个.exe, 把.exe 里的指令和数据加载到内存中,构建成一个进程,此时我们所写的这些函数所对应的二进制指令就进入内存中了,这个时候我们才能拿指针指向它。

  • 函数指针有很多用出
  1. 使用函数指针 实现转移表,降低代码的圈复杂度(就是减少 if else 的分支数目)
  2. 使用函数指针作为 回调函数。

  ——接下来就来介绍 回调函数

回调函数与普通的函数有个最明显的特点,回调函数不是你主动调用的,也不是现在就立即调用,而是把调用的机会交给别人来使用,别人会在合适的时机调用这个函数

(ps: 这个“别人” 通常是 操作系统,库,框架,别人写的代码)

接下来我们完善一下这个代码,(和上面差不多) 

执行效果也和上面一样 

除了这些还会有一些方法,这里就先不介绍了。 

 Thread 类的其他常见使用方法
 

—— Thread 的常见构造方法
 

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名
【了解】Thread(ThreadGroup group,
Runnable target)
线程可以被用来分组管理,分好的组即为线程组,这
个目前我们了解即可
  • 这俩前面刚介绍完。


  • 接下来两个,我们看看这个 name 是干啥的。 

当创建线程的时候我们可以指定 name,name不影响线程的执行,只是给线程起个名字,方便再之后调试的时候进行区分 

代码如下: 

 

我们利用 jconsole 来看一下效果(一般再 C:\Program Files\Java\jdk1.8.0_192\bin 这个路径下)

上图清晰显示出了名字。 

—— Thread 的几个常见属性
 

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

线程的身份标识,标识一个进程中唯一的一个线程(这个 id 是Java 给你这个线程分配的,不是系统API提供的线程id,更不是 PCB 中的id。) 

  • ⁜⁜⁜ 守护线程(后台线程)

——我们先了解一下前台线程 :

一个Java进程中,如果前台进程 没有执行结束,那此时的整个线程是 一定不会结束的,

相比之下,后台程序是否结束,不影响整个进程的结果。

因为一般情况下默认是前台线程,所以我们手动设为后台线程

运行一下,发现直接退出了,

改成后台程序之后,主线程飞快执行完了,此时没有其他前台线程,于是进程结束。 (t线程还没来得及执行呢,就完了)

Thread 对象的生命周期,要比系统内核中的线程更长一些,就会出现,Thread 对象还在,但是内核中的线程已经销毁了这样的情况

那此时就可以使用 isAlive()  来判断内核里的线程是否已经没了(回调方法执行完毕,线程就没了)

接下来用利用代码来看一下 

执行结果 

ps:小细节,true 和 线程开始 这两个日志不一定谁先打印。 因为线程是并发执行的,并发调度顺序不确定,取决于系统的调度器,(但大概率是先打印 true,因为调用 start 之后,新的线程创建也是有开销的,创建过程中,主线程就执行完了)

 启动线程-start() (含经典面试题,start 和 run的区别)

线程启动,start() 方法是最关键的方法

start 方法内部,是会调用到系统 API,来再系统内核中创建线程的,

相比之下,run方法,只是单纯的描述了该线程要执行的内容。(会在start 创建好线程之后自动被调用) 

中断线程 

interrupt (终止/打断) 

就是让一个线程停止运作(销毁)

在 Java 中,要销毁/终止线程,做法是比较唯一的,就是想办法让 run 方法尽快执行结束。

-- 方案一 

可以在代码中手动创建出标志位,来作为 run 的执行结束的条件。  

很多线程,执行时间久,往往是因为这里写了一个循环,循环持续很久导致的,要想让run执行结束,我们就要让 循环 尽快退出。 

----代码实现 

执行结果 

小问题: 

       当前这个代码,是使用了一个成员变量 isQuit 来作为标志位,如果把isQuit 改为 main 方法中的局部变量,是否可行呢??

  • 答:不可行
  • 原因:

上图可看见,当把isQuit 改为 main 方法中的局部变量时,while 那里报错了,

但是当把 isQuit = true 注释掉之后就不报错了,

所以我们就可以得知这里的关键是 不能修改。为什么? 

因为lambda 表达式,有个语法规则 —— 变量捕获,lambda 表达式里面的代码,是可以自动捕获到上层作用域中涉及到的局部变量 。

这个变量捕获可以理解为就是让 lambda 表达式,把当前作用域中的变量在lambda内部复制了一份。(所以此时如果外面是否销毁,就无所谓了)

但是,在Java中,变量捕获语法,还有一个前提限制,就是必须只能捕获一个 final(常量) 或者是实际上是 final 的变量。

——final 

 —— 实际上是 final

所以当下面修改的时候就一定会报错了 。

但当 isQuit 是成员变量时,lambda 访问这个成员时,就不是变量捕获这个语法了,

而是 ” 内部类访问外部类的属性“,没有final之类的限制。

所以不能把isQuit 改为 main 方法中的局部变量。

但上述方案,不够优雅,需要手动创建变量:还有当线程内部在 sleep 的时候,主线程修改变量,新线程内部不能及时响应。所以有了方案二。 

--  方案二

Tread 类内部 ,有一个现成的标志位  Thread.currentThread().isInterrupted(),可以用来判断当前的循环是否要结束。

——介绍  Thread.currentThread().isInterrupted()

ps: 注意不能直接使用 t.  ,因为此时t 还在构建当中 

通过  t.interrupt(),这个操作,就把上述的Thread对象的内部的标志位给设置成 true 了。

     ps:  而且使用  t.interrupt() 即使线程内部逻辑出现了堵塞(sleep)也是可以使用这个方法唤醒的.  正常来说,sleep会休眠到时间结束 才醒,但此处的interrupt就可以使 sleep 内部触发一个异常,从而被提前唤醒。

我们运行看看结果 

当代码sleep 那里的异常写成这样的时候 

我们就会发现,异常是抛出了但是线程没停止 

这是因为interrupt 唤醒线程之后,此时sleep 方法抛出异常,同时会自动清楚刚才设置的 标志位 

这样就使得 ”设置标志位“ 这个效果好像没有生效一样。

那为啥这么设置呢? 

       这是因为Java期望,当线程收到“要中断”这样的信号时,线程可以自由决定,接下来该如何处理。

    一般线程可以采取三种方式来进行操作:

     1.假装没听见,循环继续正常执行(就是上面的情况)

   2.加上一个 break ,表示让线程立即结束。 

运行效果,线程立刻就结束了。 

 3. 可以在break,前做一些其他工作,完成之后在结束

这样就让我们程序员有更多的 “可操作性空间”   (“可操作性空间” 的前提是 通过 “异常”的方式唤醒的,如果没有sleep,就没有上述的操作空间) (就是没有异常那就正常执行,有异常我们就要再确认一下,看看怎么回事)

ps: IntelliJ IDEA Community Edition 2022.3.3 这个版本的IDEA,生成的try-catch是这样的,

执行之后是可以结束的 

  

线程等待 

有时,我们需要等待一个线程完成它的工作后,才能进行下一步工作 。

本质上就是控制线程结束的顺序。

方法说明
public void join()等待线程结束
public void join(long millis)等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos)同理,但可以更高精度

“join() 方法”就是实现线程等待效果的。(在哪个线程里调用了join,哪个线程就阻塞) 

如果在主线程中,调用t.join(), 那此时就是主线程等待t 线程,等待t 线程结束。

利用代码,我们能清晰的看见join的效果。 

 

执行效果 

 

t.join 工作过程

  • 如果 t 线程正在运行,那此时调用 join 的线程就会阻塞,一直阻塞到  t 线程执行结束。
  • 如果 t 线程已经执行结束了,那此时调用 join 线程,就直接返回了,不会阻塞。
  • 如果 t 线程一直不结束,join 默认情况下是 “一直等待的”。

但是一直等待不现实,一般,等待操作都有一个“超时时间”,就有了第二个方法  

public void join(long millis)。等待线程结束,最多等 millis 毫秒。

╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯完 ╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯

 

 

 

 

 

 

   

 

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

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

相关文章

webrtc 的Bundle group 和RTCP-MUX

1,最近调试程序的时候发现抱一个错误 max-bundle configured but session description has no BUNDLE group 最后发现是一个参数设置错误 config.bundle_policy webrtc::PeerConnectionInterface::BundlePolicy::kBundlePolicyMaxBundle; 2,rtcp-mu…

SpringBoot项目,执行install命名时,控制台显示:Unable to find main class

构建springboot多模块项目,启动时可以正常启动,执行了父工程的maven的clean也没问题,执行install的时候就报错了:Unable to find main class。显而易见 这个错是找不到主类。 记录下解决过程: 首先看自己项目的父工程…

膦酸基官能团高盐环境下去除钙镁离子树脂

项目名称 某新能源公司除钙镁项目 工艺选择 串联运行 工艺原理 膦酸基官能团高盐环境下去除钙镁离子 项目背景 锂及其盐类是国民经济和国防建设中具有重要意义的战略物资,也是与人们生活息息相关的能源材料。而碳酸Li作为锂盐的基础盐,是制取锂化…

Matlab 基本教程

1 清空环境变量及命令 clear all % 清除Workspace 中的所有变量 clc % 清除Command Windows 中的所有命令 2 变量命令规则 (1)变量名长度不超过63位 (2)变量名以字母开头, 可以由字母、数字和下划线…

vue3路由跳转以及传参。和vue2路由跳转传参的区别

路由的安装和引入以及注册就不过多赘述,直接说区别和怎么跳转页面 vue2路由跳转以及传递参数 vue2只需要创建好router文件夹和index.js,配置好我们的路由,在main.js引入 import router from "/router"; // vue路由app.use(route…

如何避免重复消费消息

博主介绍:✌全网粉丝3W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…

【函数栈帧解析:代码的迷人堆积和无限嵌套】

本章重点 一、何为函数栈帧 二、函数栈帧特性 - 同栈 - 后进先出 三、认识内存空间布局图 四、认识相关寄存器 五、认识相关汇编命令 六、测试代码: 七、函数栈帧全过程 要解决的问题​​​​​​​ 局部变量是怎么创建的?为什么局部变量的值是随机值&am…

10项必备的IT国际认证

10项必备国际IT认证对于希望在数字时代提升职业生涯的专业人士来说,已成为一项重要资产。 此类认证不仅肯定了你在特定IT领域的专业知识,还展现了你会在以后的生涯中不断学习和专业成长的决心。为了帮助你查询这些选择,我们编制了一份2023年…

华为OD机试 - 租车骑绿道 - 双指针(Java 2023 B卷 100分)

目录 一、题目描述二、输入描述三、输出描述四、解题思路1、输入2、输出3、说明4、双指针算法 五、Java算法源码六、效果展示 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 一、题目描述 部门组织绿岛骑行团建活动,租用公共双人自行车骑行,…

装箱、拆箱

装箱:将基本类型用它们对应的引用类型包装起来;拆箱:将包装类型转换为基本数据类型; Java 可以自动对基本数据类型和它们的包装类进行装箱和拆箱。 为什么要有包装器类型 因为java的三种集合,List、Set、Map&#xf…

【python零基础入门学习】python基础篇之判断与for循环(二)

本站以分享各种运维经验和运维所需要的技能为主 《python》:python零基础入门学习 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8》暂未更新 《docker学习》暂未更新 《ceph学习》ceph日常问题解…

iTOP-RK3588开发板Android12 设置系统默认不休眠

修改文件&#xff1a; device/rockchip/rk3588/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults. xml 文件&#xff0c;如下图所示&#xff1a; - <integer name"def_screen_off_timeout">60000</integer> <integer name&q…

电子相册制作新技巧,让你惊叹不已!

​近年来&#xff0c;随着科技的不断进步&#xff0c;电子相册制作已经成为了一种流行的趋势。无论是记录旅行的美好瞬间&#xff0c;还是展示生活中的点滴幸福&#xff0c;电子相册都能够将这些珍贵的回忆永久保存下来。 在我们制作电子相册之前&#xff0c;我们需要选择一款专…

QQ邮件营销

邮件营销效果好的莫过于QQ邮件营销&#xff0c;QQ邮件收件会自动弹窗提示&#xff0c;邮件的阅读率是所有目前邮箱中最高的&#xff0c;而QQ邮件规则使用的叶贝思反垃圾邮件算法会有效防止一般的群发邮件&#xff0c;一米智能QQ邮件营销系统针对性的解决了这个难题。另外我们对…

00. 深入编程原理系列文章前言

名称的含义 为什么要用《从0到1&#xff0c;第一行代码》这个名字&#xff0c;有两重含义&#xff1a; 有一本很著名的书&#xff0c;就叫《从0到1》&#xff0c;表示从无到有的意思&#xff0c;这里也叫从0到1&#xff0c;表示代码到底怎么来的&#xff0c;程序到底是怎么运行…

Java 数据库改了一个字段, 前端传值后端接收为null问题解决

前端传值后端为null的原因可能有很多种&#xff0c;我遇到一个问题是&#xff0c;数据库修改了一个字段&#xff0c;前端传值了&#xff0c;但是后台一直接收为null值&#xff0c; 原因排查&#xff1a; 1、字段没有匹配上&#xff0c;数据库字段和前端字段传值不一致 2、大…

事前规划,事半功倍!与大家聊聊项目管理的重要性

大家好&#xff0c;我是你们的小米&#xff01;希望大家都过得开开心心&#xff0c;工作顺利&#xff0c;生活美满。今天我要和大家分享一个让我深有感触的话题——项目管理中的事前规划&#xff0c;以及它所带来的重要性。就在昨晚&#xff0c;我经历了一次让人啼笑皆非的经历…

数据通信——DHCP中继

一&#xff0c;实验背景 之前不是用DHCP来分配IP地址么&#xff01;现在该公司在核心交换机旁挂了一个专用的 DHCP Server 来为终端分配IP地址&#xff0c;那么现在你就要改下配置了&#xff0c;用DHCP中继完成IP分配。 中继的好处就是&#xff0c;我们仅需在中继上配好DHCP所需…

HarmonyOS扫码服务,应用服务一扫直达打造系统级流量新入口

二维码如今是移动应用流量入口以及功能实现的重要工具&#xff0c;也是各App的流量入口&#xff0c;是物、人、服务的连接器&#xff0c;通过扫码我们可以更便捷的生活&#xff0c;更高效的进行信息交互&#xff0c;包括信息的发布、信息的获取。 在日常扫码过程中&#xff0c…

机器学习面试的12个基础问题

毕业季找工作了&#xff1f;如果想应聘机器学习工程师岗位&#xff0c;你可能会遇到技术面试&#xff0c;这是面试官掂量你对技术的真正理解的时候&#xff0c;所以还是相当重要的。近日&#xff0c;JP Tech 发表了一篇文章&#xff0c;介绍了他们面试新人时可能会提出的 12 个…