当前位置: 首页 > news >正文

【JAVAEE学习】探究Java中多线程的使用和重点及考点

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶​
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客

系列专栏:xiaoxie的JAVAEE学习系列专栏——CSDN博客●'ᴗ'σσணღ
我的目标:"团团等我💪( ◡̀_◡́ ҂)" 

( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​+关注(互三必回)!

目录

​编辑一.线程

  1.什么是线程

2.进程和线程的区别

1.在这里先解释一下最基础的定义

2.举个我们日常生活中的小例子

3.线程和进程的区别以及线程相比于进程的优点:(这个面试中也算是比较高频的问题)

二.编写多线程代码

1.定义线程类

1.说明

2.通过实现Runnadle接口创建线程

3.针对方法1使用匿名内部类

 4.针对方法2使用匿名内部类

5.使用 lambda表达式

三.Thread类

1.构造方法

2.其他的方法

1.获取Id getid()

 ​编辑  2.获取名称 getName()

3.获取状态 getState()

4.是否为后台线程 isDaemon()

​编辑 5.是否存活 isAlive()

6.是否被中断 isInterrupted()


一.线程

  1.什么是线程

线程(Thread)是程序中执行的最小单元,是操作系统能线程是计算机科学中的基本概念,指的是在同一进程中执行的单一执行流。线程是操作系统能够进行运算调度的最小单位。在多线程编程中,多个线程可以同时执行,共享进程的资源,但每个线程有自己的执行流程和栈空间。线程的引入可以提高程序的并发性和响应性,允许程序在同一时间处理多个任务。

在计算机系统中,线程是由操作系统调度和管理的,可以实现不同线程之间的切换和协同工作。线程之间可以共享进程的资源,如内存空间、文件描述符等,但也需要注意线程之间的同步和互斥,以避免竞态条件和数据不一致问题。

在编程中,线程可以用来实现并发编程,允许程序同时执行多个任务,提高程序的性能和效率。常见的多线程编程模型包括线程池、生产者-消费者模型等

2.进程和线程的区别

这个先解释一下线程和进程的区别,这个两个词虽然看起来相差不大,但意思却相差很大,当对于初学者来说还是比较容易混淆的

1.在这里先解释一下最基础的定义

    进程:在计算机操作系统中,进程是对运行中程序的一个抽象,它是系统进行资源分配和调度的基本单位。每个进程都有自己独立的地址空间,包含了程序代码、数据、打开的文件描述符等资源。当一个程序开始执行时,操作系统会为其创建一个新的进程,使得程序可以占用系统资源并独立运行

     线程:线程是进程内的一个执行路径,也是CPU调度的最小单位一个进程中可以有一个或多个线程(每个进程都有最基本的主线程),这些线程共享进程的相同地址空间(包括代码、全局变量等资源)。每个线程都维护有自己的程序计数器、寄存器集合和栈,这样它们就可以在进程的上下文中并发执行各自的任务。相较于进程,线程之间的切换成本更低,而且由于资源共享的特性,线程间的通信和同步更为简便。

2.举个我们日常生活中的小例子

用日常生活的例子来解释进程和线程的区别:

进程比喻: 想象一个餐厅,每个餐厅就是一个进程,它有自己独立的厨房(资源)、服务员(线程)、菜单(程序)、餐桌(内存空间)和客户账单(数据)。如果有两家不同的餐厅(两个进程),它们各自运营,拥有各自的食材和设备,互不影响,也不能直接共享对方的东西。

线程比喻: 回到同一个餐厅内,如果餐厅有多个服务员(线程),他们共享餐厅的所有资源(如厨房、菜单等),并且能在同一餐厅的不同区域同时服务多个顾客。比如,一个服务员负责点菜(处理请求),另一个负责上菜(执行任务),还有一个负责结账(清理资源)。虽然他们在同一片工作区(地址空间)内同时活动,但会通过合理的协调(例如,加锁机制)来避免冲突。

总结来说,在这个比喻中:

  • 进程就像是独立运作的餐厅,每个餐厅有一套完整的设施和人员;
  • 线程则是同一餐厅内的不同服务员,他们共享餐厅资源并在其中执行各自的任务,可以同时服务于不同的顾客,实现并发操作。

3.线程和进程的区别以及线程相比于进程的优点:(这个面试中也算是比较高频的问题)

  1. 资源分配

    • 进程:进程是操作系统进行资源分配和保护的基本单位,每个进程都有独立的内存空间,其中包括代码段、数据段、堆和栈。这意味着不同进程之间无法直接访问彼此的内存空间,从而保证了进程间的隔离性。
    • 线程:线程是进程内部的执行实体,是系统调度和分配CPU的基本单位。同一进程内的所有线程共享相同的地址空间(包括全局变量、文件描述符等资源),也就是说,线程间可以直接读写同一进程内的内存,无需通过IPC(进程间通信)机制。
  2. 创建和切换开销

    • 进程创建新进程需要分配独立的地址空间和其他相关资源,因此开销较大。进程间的切换除了保存和恢复CPU上下文外,还可能涉及虚拟内存、页表等映射的切换,开销相对较高。
    • 线程创建线程的成本比进程低得多,因为它不需要额外分配地址空间。线程间的切换只需要保存和恢复少量寄存器状态(如程序计数器、栈指针等),因此线程切换的开销较小。
  3. 并发性和并行性

    • 进程:进程提供了并发执行的能力,即在单个处理器上通过时间片轮转实现看似同时运行的效果,而在多处理器环境下,则可以真正地并行执行不同的进程。
    • 线程:线程提供了更加细粒度的并发执行,一个进程中的多个线程可以在单个处理器上通过时间片轮转并发执行,也可以在多核处理器上真正并行执行。
  4. 通信与同步

    • 进程:进程间的通信通常需要使用IPC机制,如管道、信号量、消息队列、共享内存等。
    • 线程:由于同一进程内的线程共享内存空间,它们之间的通信和同步可以通过更简单的机制实现,如锁、条件变量等。
  5. 管理复杂性

    • 进程:进程管理相对复杂,需要考虑资源的独立性和安全性。
    • 线程:线程管理更加灵活,但由于线程间的资源共享特性,可能导致竞态条件死锁等(涉及到线程安全问题)问题,因此线程同步和互斥问题较为复杂。

综上所述,进程是操作系统中资源分配和保护的基本边界,而线程则是提供更高效并发执行能力的基础,并且在线程之间更容易共享信息和协同工作。

二.编写多线程代码

1.定义线程类

class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("hello Thread");try {Thread.sleep(1000);//使线程休眠} catch (InterruptedException e) {e.printStackTrace();}}}
public class Demo1 {}public static void main(String[] args)  {Thread thread = new MyThread();thread.start();//创建线程while (true) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

运行结果:

 我们可以看到主线程和Thread线程在交替打印各自的信息需要注意的是,实际运行时,由于线程调度机制,线程间的执行并不是严格按照交替顺序进行的,而是随机交错的。

同时我们还可以通过命令行的方式查看线程运行的状态

WIN + R 后输入cmd打开命令行后输入jconsole

点击我们刚才创建好的线程 

 看到这里提醒不安全连接我们不用理会直接点击

 此时我们就清楚的看见线程的状态以及其它信息

1.说明

我们可以看到如果使单线程运行的化,此时陷入了死循环,应该无限循环不断地输出"hello Thread",但就是因为多线程操作并发操作程序实现了两个并发执行的线程:主线程和MyThread子线程。这两个线程交替打印各自的信息,同时还可以发现,打印时并不是严格按照交替顺序进行,而是随机交错但由于线程调度的不确定性,(抢占执行)实际输出的结果可能会出现交错现象,比如连续输出多次"hello Thread"后再输出几次"hello main",或者是反过来的情况,这就是线程随机交错的现象。

同时在这里解释一下

 1.首先定义了一个名为MyThread的类,该类继承自java.lang.Thread。在MyThread类中重写了run()方法,这个方法是线程需要执行的任务主体。在run()方法内部,有一个无限循环不断地输出"hello Thread",并且每次循环之间让当前线程睡眠1秒通过Thread.sleep(1000)实现并且实现这个方法需要抛异常

2.创建线程实例:在main方法中,创建了MyThread类的一个实例thread。启动线程:调用thread.start()方法来启动线程。这会让JVM找到这个线程对象的run()方法,并在一个新的线程上下文中执行它

 为什么要调用thread.start()  (这一点很重要)

在Java中,当你想要启动一个新的线程去执行特定任务时,你需要调用Thread对象的start()方法。这是因为start()方法的作用是让JVM创建一个新的线程,并在这个新线程中调用你之前重写的run()方法

具体来说:

  • 当你创建一个Thread对象实例时,只是在内存中构建了一个表示线程的对象,并没有真正开启一个新的执行流。
  • 而当你调用start()方法时,Java虚拟机会为此线程分配必要的系统资源(如内存),并在某个时刻将该线程放入可执行线程队列等待调度。
  • 线程调度器会选择合适的时机将该线程从就绪状态转为运行状态,这时run()方法才会在新创建的线程上下文中执行。

因此,如果你直接调用run()方法而不是start()方法,那么代码将在当前线程(通常是主线程)中同步执行,而非异步在新的线程中执行,也就失去了多线程的意义。

2.通过实现Runnadle接口创建线程

class MyRunnable implements Runnable {@Overridepublic void run() {while (true) {System.out.println();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Demo2 {public static void main(String[] args)  {Thread t = new Thread(new MyThread());t.start();while (true) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

 定义Runnable接口的实现类:MyRunnable类实现了java.lang.Runnable接口,并在其内部重写了run()方法。这个run()方法同样是线程需要执行的任务主体,这里也是一个无限循环,每秒输出一行空白字符,并在每次循环间使当前线程睡眠1秒。

输出结果和第一种方法同样主线程和Thread线程在交替打印各自的信息,同样不是严格按照交替顺序进行的,而是随机交错

  

3.针对方法1使用匿名内部类

public class Demo3 {public static void main(String[] args) {Thread t = new Thread() {@Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}};t.start();while (true) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}

就是针对方法1的一个变种方法,结果都一样,都是实现了多线程

  

 4.针对方法2使用匿名内部类

public class Demo4 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(new Runnable() {@Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});t.start();while (true) {System.out.println("hello main");Thread.sleep(1000);}}
}

 就是针对方法2的一个变种方法,结果都一样,都是实现了多线程

  

5.使用 lambda表达式

public class Demo5 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (true) {System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();while (true) {System.out.println("hello main");Thread.sleep(1000);}}
}

Lambda表达式是Java 8及其后续版本引入的一种简洁的函数式编程风格的特性,用于创建匿名函数或闭包。Lambda表达式使得开发者能够更加方便地处理函数式接口(即只有一个抽象方法的接口),无需显式声明新的类来实现这些接口。

基本结构: Lambda表达式的通用格式如下:

Java

1(parameters) -> {body}
  • 参数部分(parameters):可以为空,也可以包含零个或多个参数。每个参数都有一个类型或可以通过类型推断得出。如果只有一个参数,可以省略小括号;如果有多个参数,则需用逗号分隔。

  • 箭头符号(->):标志着参数列表的结束和函数体的开始。

  • 函数体(body):可以是一个表达式或一个代码块。如果函数体只包含一条表达式且能隐式转换为方法的返回类型,可以省略大括号;否则,需要使用大括号包围多条语句形成代码块。

 结果如下:

  

这5种方法博主这里建议大家不说你都会写,(当然这5种方法多写几遍,应该差不多就可以掌握了)但你至少都得看的懂,并且熟练掌握几种.其实这5种方法本质上就是

1.把线程具体要实现的业务写出来即(重写run()方法)

2.通过调用start()方法创建/启动线程.

三.Thread类

1.构造方法

T​​​​hread(String name)这里可以为你创建的线程,命名以便在后续这个名字对于理解和追踪多线程应用程序中的各个线程很有帮助,尤其是在调试和日志记录的过程中。

public class Demo23 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()-> {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("hello Thread");}},"text1");t1.start();while (true) {Thread.sleep(1000);System.out.println("hello main");}}
}

通过命令行输入jconsole打开Java的监视控制台就可以查看到,此时我们创建的线程的状态,非常便于识别和管理各个线程特别是在后期我们创建很多线程时,优势就体现出来了

  

2.其他的方法

1.获取Id getid()

public class Demo23 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()-> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("hello thread");},"text1");t1.start();System.out.println(t1.getId());//获取线程的IDThread.sleep(1000);System.out.println("hello main");}
}

结果为:

   2.获取名称 getName()

3.获取状态 getState()

4.是否为后台线程 isDaemon()

这里我们介绍一下后台线程和前台线程的区别

  1. 前台线程(Foreground Thread)

    • 常指那些负责处理用户交互、执行主业务逻辑或执行关键服务的线程,这类线程通常决定了整个应用程序的生命周期。例如,GUI应用程序的事件循环线程就是一个典型的前台线程,只要这个线程还在运行,应用程序就不会退出。另外,Web服务器中的请求处理线程也是前台线程,它们必须保持活跃以响应客户端请求。
  2. 后台线程(Background Thread)

    • 也称为守护线程(Daemon Thread)。在Java中,通过调用 Thread.setDaemon(true) 方法可以将一个线程设置为守护线程。守护线程主要用于执行支持性的任务,比如清理工作、资源监控、定时任务等。当所有的非守护线程(也就是所谓的前台线程)都结束后,即使还有守护线程在运行,Java虚拟机也会退出。也就是说,守护线程依赖于非守护线程的存在,非守护线程全部结束后,守护线程也随之结束,不再单独维持应用程序的运行。

总结来说,前台线程与应用程序的主要功能和生命周期紧密相关,而后台线程则更多是服务于前台线程,不直接影响应用程序的关闭与否

为了通俗易懂点博主这里举个小例子

  1. 前台线程(重要主线任务)

    • 假设你正在厨房做饭(这是你的主要任务,类似于前台线程),你正在炒菜(主业务流程),这个过程中你需要不断地翻炒、调味等操作(前台线程的工作)。如果不做这些,饭就无法完成,这就是至关重要的前台任务。
  2. 后台线程(辅助支持任务)

    • 同时,厨房里的洗碗机正在运行清洗餐具(这是一个后台守护任务,类似于后台线程)。虽然洗碗很重要,但如果炒菜任务完成了(所有非守护线程结束),你可以离开厨房,即使洗碗机还没洗完(后台线程仍在运行),你也不会留在那里等待它结束。洗碗机就是在后台默默地支持你的主要烹饪任务。

通过这个例子,可以看出前台线程(炒菜)主导着整个活动的进程和结束,而后台线程(洗碗机)虽然重要,但它的运行并不影响整个活动(做饭)的基本结束条件。在计算机程序中,后台线程往往用来处理一些辅助性、长期运行或维护性的工作,而不直接影响程序的主流程和退出。

再通过具体的代码例子来说明后台线程和前台线程

这个属于两个都是前台线程的情况

public class Demo25 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for(int i = 0; i <5;i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("hello Thread");}System.out.println("t1结束");});t1.start();for (int i = 0;i < 3;i++) {Thread.sleep(1000);System.out.println("hello main");}System.out.println("main结束");}
}

 

可以看到,main线程以及结束了,可是t1线程没有结束,此时进程就没有结束,直到t1结束后,进程才结束,这就是只有所有前台线程结束后,进程才结束

我们现在把t1线程设置为后台线程再看看结果如何

这里要注意在创建线程之前(在start()方法之前),就要先设置好,否则此操作无效

public class Demo25 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for(int i = 0; i <5;i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("hello Thread");}System.out.println("t1结束");});t1.setDaemon(true);//要在线程创建前,将线程设置为后台线程t1.start();for (int i = 0;i < 3;i++) {Thread.sleep(1000);System.out.println("hello main");}System.out.println("main结束");}
}

此时,main线程为前台线程,t1为后台线程,我们可以看到只要main线程结束了,无论t1是否结束,进程都结束了.以及如果t1结束,但前台线程main线程没有结束,进程也不会结束

public class Demo25 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for(int i = 0; i <3;i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("hello Thread");}System.out.println("t1结束");});t1.setDaemon(true);//要在线程创建前,将线程设置为后台线程t1.start();for (int i = 0;i < 5;i++) {Thread.sleep(1000);System.out.println("hello main");}System.out.println("main结束");}
}

 5.是否存活 isAlive()

它用于检查一个线程是否仍然存活,即线程是否已经开始执行且还没有结束。

6.是否被中断 isInterrupted()

isInterrupted() 是Java中 Thread 类的一个方法,用于检查线程是否已被中断。中断是一种协作机制,允许一个线程通知另一个线程应该停止当前正在执行的操作。

语法如下:

Java

1boolean isInterrupted()

这个方法会返回一个布尔值:

  • 如果线程已被中断(调用了 interrupt() 方法),则返回 true
  • 如果线程未被中断,则返回 false

需要注意的是,调用 isInterrupted() 方法并不会清除中断状态。如果希望在检查中断状态的同时清除此状态,可以使用静态方法 Thread.interrupted()

举例说明:

Java

1Thread thread = new Thread(() -> {
2    while (!Thread.currentThread().isInterrupted()) {
3        // 执行任务...
4    }
5});
6
7thread.start();
8
9// 在某个时刻,决定中断线程
10thread.interrupt();
11
12// 另一线程或同一线程中的代码可以通过isInterrupted()检查中断状态
13if (thread.isInterrupted()) {
14    System.out.println("线程已被中断");
15}

在上面的代码中,线程在执行任务时会周期性检查自身的中断状态,一旦发现被中断,就会退出循环,从而达到协作式中断的目的

同时需要注意的是,只能起到提醒作用,并不可以真正的中断,这能该线程自己中断自己

例如,线程可能在循环、等待IO操作、或者在调用 sleep()wait()join() 等方法时被中断。在这些情况下,被中断的线程通常会抛出一个 InterruptedException 异常,然后可以根据程序的需求选择恢复执行、清理资源后退出,或者直接结束线程。

总的来说,interrupt() 方法和 isInterrupted() 方法提供了线程间的通信手段,允许一个线程请求另一个线程停止其当前的操作,但具体的中断逻辑需要由被中断线程自行实现,体现了Java中线程中断的协作性和灵活性。

以上就是博主关于Java多线程学习的一点点部分,后续还有很多内容,例如重点的:线程安全问题

这里就不过多的赘述了,如果感兴趣的话,可以关注博主.查看线程安全的解释

相关文章:

【JAVAEE学习】探究Java中多线程的使用和重点及考点

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…...

Day81:服务攻防-开发框架安全SpringBootStruts2LaravelThinkPHPCVE复现

目录 PHP-框架安全-Thinkphp&Laravel Laravel CVE-2021-3129 RCE Thinkphp 版本3.X RCE-6.X RCE 版本6.X lang RCE J2EE-框架安全-SpringBoot&Struts2 Struct2 旧漏洞(CVE-2016-0785等) struts2 代码执行 &#xff08;CVE-2020-17530&#xff09;s2-061 Str…...

.kat6.l6st6r勒索病毒肆虐,这些应对策略或许能帮到你

引言&#xff1a; 近年来&#xff0c;网络安全问题日益凸显&#xff0c;其中勒索病毒更是成为了公众关注的焦点。其中&#xff0c;.kat6.l6st6r勒索病毒以其独特的传播方式和破坏力&#xff0c;给全球用户带来了极大的困扰。本文将深入探讨.kat6.l6st6r勒索病毒的特点&#xf…...

maya移除节点 修改节点

目录 maya移除节点 使用 Maya 用户界面&#xff1a; 使用脚本&#xff1a; maya 修改节点名字 使用 Maya 用户界面&#xff1a; 使用 MEL 脚本&#xff1a; 使用 Python 脚本&#xff1a; 注意事项&#xff1a; maya移除节点 使用 Maya 用户界面&#xff1a; 在“层次…...

嵌入式算法开发系列之卡尔曼滤波算法

卡尔曼滤波算法 文章目录 卡尔曼滤波算法前言一、卡尔曼滤波算法原理二、算法应用三、C语言实现总结 前言 在嵌入式系统中&#xff0c;传感器数据通常受到噪声、误差和不确定性的影响&#xff0c;因此需要一种有效的方法来估计系统的状态。卡尔曼滤波算法是一种基于概率理论的…...

简述对css工程化的理解

一、css工程化解决了哪些问题 1、宏观设计&#xff1a;css如何组织、拆分、设计模块结构 2、编码优化&#xff1a;如何更好地编写css 3、构建&#xff1a;如何处理css&#xff0c;使打包结果最优 4、可维护性&#xff1a;最小化后续的变更成本 二、针对问题&#xff0c;如何解…...

.NET 5种线程安全集合

在.NET中&#xff0c;有许多种线程安全的集合类&#xff0c;下面介绍五种我们常用的线程安全集合以及他们的基本用法。 ConcurrentBag ConcurrentBag 是一个线程安全的无序包。它适用于在多线程环境中频繁添加和移除元素的情况。 ConcurrentBag<int> concurrentBag n…...

计算机信息自查

文章目录 操作系统安装时间硬盘序列号查询上网IPMAC地址 操作系统安装时间 可以使用命令行形式&#xff0c;查询windows系统安装时间&#xff1a; wmic OS get InstallDate首先显示年份&#xff0c;然后是月份&#xff0c;然后是日期&#xff0c;然后是安装的确切时间 或者w…...

配置vite配置文件更改项目端口、使用@别名

一、配置vite配置文件更改项目端口 vite官方文档地址&#xff1a;开发服务器选项 | Vite 官方中文文档 (vitejs.dev) 使用&#xff1a; 二、使用别名 1. 安装 types/node types/node 包允许您在TypeScript项目中使用Node.js的核心模块和API&#xff0c;并提供了对它们的类型…...

【LeetCode热题100】【链表】环形链表

题目链接&#xff1a;141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 判断一个链表有没有环可以用快慢指针的方法&#xff0c;如果没有环&#xff0c;那么最终可以让两个指针中一个为空&#xff0c;如果有环&#xff0c;那么快指针终会与慢指针相遇 class Solution {…...

SpringBoot整合ELK8.1.x实现日志中心教程

目录 背景 环境准备 环境安装 1.JDK安装 2.安装Elasticsearch 3.安装zookeeper 4.安装Kafka 5.安装logstash 6.安装file beat 解决方案场景 1.日志采集 1.1 应用日志配置 1.1.1 创建logback-spring.xml文件 1.1.2 创建LoggerFactory 1.1.3 trace日志的记录用法 …...

计算机网络:数据链路层 - 封装成帧 透明传输 差错检测

计算机网络&#xff1a;数据链路层 - 封装成帧 & 透明传输 & 差错检测 数据链路层概述封装成帧透明传输差错检测 数据链路层概述 从数据链路层来看&#xff0c;主机 H1 到 H2 的通信可以看成是在四段不同的链路上的通信组成的&#xff0c;所谓链路就是从一个节点到相邻…...

Open3D (C++) 计算点云的特征值特征向量

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 针对整个点云 P = { p i } i...

Java | Leetcode Java题解之第8题字符串转换整数atoi

题目&#xff1a; 题解&#xff1a; class Solution {public int myAtoi(String str) {Automaton automaton new Automaton();int length str.length();for (int i 0; i < length; i) {automaton.get(str.charAt(i));}return (int) (automaton.sign * automaton.ans);} …...

BL200耦合器数据采集模块

BL200耦合器数据采集模块是一个数据采集和控制系统&#xff0c;基于强大的32 位ARM926EJ-S™ 微处理器设计&#xff0c;采用Linux操作系统&#xff0c;支持Modbus TCP协议&#xff0c;可以快速接入现场PLC、MES、Ignition和SCADA以及ERP系统&#xff0c;同时也能快速连接到AWS云…...

基于Uni-app的体育场馆预约系统的设计与实现

个人介绍 hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的…...

1.Spring Boot框架整合

Spring Boot项目创建&#xff08;约定大于配置&#xff09; 2.1.3.RELEASE版本示例 idea创建 从官网下载&#xff08;https://start.spring.io/&#xff09;单元测试默认依赖不对时&#xff0c;直接删除即可 Web支持&#xff08;SpringMVC&#xff09; <dependency>&…...

如何在 Debian VPS 上添加、删除和授予用户 sudo 权限

简介 当你启动一个新的服务器时&#xff0c;会创建一个名为 root 的默认账户。这个用户拥有完全的系统访问权限&#xff0c;应该仅用于管理任务。作为 root 用户&#xff0c;你基本上可以对系统做任何操作&#xff0c;这很强大&#xff0c;但也极其危险。Linux 没有“撤销”按…...

openlayers 入门教程(九):overlay 篇

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…...

基于Python的高考志愿辅助填报系统

基于Python的高考志愿辅助填报系统是一个利用数据分析和机器学习技术帮助高考生进行志愿填报决策的工具。该系统可以根据考生的分数、兴趣、专业偏好、历史录取数据等因素&#xff0c;为考生提供科学合理的志愿填报建议。以下是设计这样一个系统的步骤和要点。 ### 1. 数据收集…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...