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

第四天面试题

文章目录

  • 1.什么叫 Java 的内存泄露与内存溢出?
      • **1. 内存泄露(Memory Leak)**
        • **内存泄露的常见原因:**
        • **如何避免内存泄露:**
      • **2. 内存溢出(Out Of Memory, OOM)**
        • **内存溢出的常见原因:**
        • **如何避免内存溢出:**
      • **内存泄露与内存溢出的关系**
      • **示例代码**
        • **内存泄露示例:**
        • **内存溢出示例:**
      • **总结**
  • 2.java 中数据在内存中是如何存储的?
      • **1. 栈(Stack)**
        • **栈中存储的内容:**
        • **示例:**
      • **2. 堆(Heap)**
        • **堆中存储的内容:**
        • **示例:**
      • **3. 方法区(Method Area)**
        • **示例:**
      • **4. 本地方法栈(Native Method Stack)**
      • **5. 程序计数器(Program Counter Register)**
      • **数据存储的总结**
      • **示例代码分析**
      • **总结**
  • 3.Error 和 Exception 的区别?
      • **1. Error**
        • **Error 的特点:**
        • **常见的 Error 类型:**
        • **示例:**
      • **2. Exception**
        • **Exception 的特点:**
        • **常见的 Exception 类型:**
        • **示例:**
      • **Error 和 Exception 的区别**
      • **总结**
  • 4.常见的异常有哪些?
  • 5.请说一下递归的概念?
  • 6.try...catch...finally的作用?
      • 1. **`try` 块**
      • 2. **`catch` 块**
      • 3. **`finally` 块**
      • 执行顺序
      • 示例代码
      • 使用场景
      • 注意事项
  • 7.try...catch...finally执行顺序问题?
      • 1. **正常情况(无异常)**
      • 2. **发生异常**
      • 3. **`try` 或 `catch` 中有 `return`**
      • 4. **`finally` 中有 `return`**
      • 5. **`try` 或 `catch` 中有 `System.exit()`**
      • 总结
  • 8.throws 和 throw 的区别?
      • 1. **`throw`**
      • 2. **`throws`**
      • 3. **`throw` 和 `throws` 的区别**
      • 4. **结合使用的示例**
      • 5. **总结**
  • 9.final,finally 和 finalize 的比较?
      • 1. `final`
      • 2. `finally`
      • 3. `finalize`
      • 总结
  • 10.进程和线程的区别?
      • 1. **定义**
      • 2. **资源分配**
      • 3. **创建和销毁的开销**
      • 4. **独立性**
      • 5. **并发性**
      • 6. **应用场景**
      • 7. **示例**
      • 总结对比表
      • 选择进程还是线程?
  • 11.并行和并发?
      • 1. **定义**
      • 2. **核心区别**
      • 3. **实现方式**
      • 4. **适用场景**
      • 5. **示例**
      • 6. **类比**
      • 7. **总结对比表**
      • 8. **并发与并行的关系**
      • 9. **编程模型**
      • 总结
  • 12.JVM 的启动是多线程的吗
      • 主要后台线程
      • 总结
  • 13.多线程的创建方式?
      • 1. **继承 `Thread` 类**
      • 2. **实现 `Runnable` 接口**
      • 3. **实现 `Callable` 接口**
      • 4. **使用线程池**
      • 5. **使用 Lambda 表达式(Java 8+)**
      • 总结
  • 14.继承Thread类和实现Runnable接口的对比?
      • 1. **继承 `Thread` 类**
        • 实现方式
        • 优点
        • 缺点
      • 2. **实现 `Runnable` 接口**
        • 实现方式
        • 优点
        • 缺点
      • 对比总结
      • 推荐使用场景
      • 示例:资源共享场景
  • 15.什么是守护线程?
      • 守护线程的特点
      • 守护线程的创建
      • 守护线程 vs 非守护线程
      • 注意事项
      • 示例:守护线程的应用
      • 总结
  • 16.线程的生命周期?
      • 线程的 5 种状态
      • 1. **新建状态(NEW)**
      • 2. **就绪状态(RUNNABLE)**
      • 3. **运行状态(RUNNING)**
      • 4. **阻塞状态(BLOCKED)**
      • 5. **等待状态(WAITING)**
      • 6. **超时等待状态(TIMED_WAITING)**
      • 7. **终止状态(TERMINATED)**
      • 线程状态转换图
      • 示例代码:观察线程状态
      • 总结
  • 17.阻塞状态的分类?
      • 1. **等待阻塞(Waiting)**
      • 2. **阻塞阻塞(Blocked)**
      • 3. **定时阻塞(Timed Waiting)**
      • 总结
  • 18.什么线程安全问题?
  • 19.什么是线程同步?

1.什么叫 Java 的内存泄露与内存溢出?

内存泄漏(memoryleak):就是存在一些被分配的对象但是这些对象不会再被使用,仍存在该内存对象的引用,导致无法释放内存空间。一次内存泄露危害可以忽略,但是任其发展最终会导致内存溢出,如读取文件后流要及时关闭、数据库连接要及时释放。

内存溢出(outofmemory):就是指应用程序在申请内存时,没有足够的内存空间供其使用。如我们在项目中对于大批量数据的导入,尽量采用分批提交的方式

Java 中的 内存泄露(Memory Leak)内存溢出(Out Of Memory, OOM) 是两个不同的概念,但它们都与内存管理相关。


1. 内存泄露(Memory Leak)

内存泄露是指程序在运行过程中,由于某些原因未能释放不再使用的对象,导致这些对象占用的内存无法被回收,从而造成内存的浪费。随着时间的推移,内存泄露会逐渐累积,最终可能导致内存溢出。

内存泄露的常见原因:
  • 静态集合类:静态集合(如 static Liststatic Map)会一直持有对象的引用,导致对象无法被回收。
  • 未关闭的资源:如数据库连接、文件流、网络连接等未显式关闭。
  • 监听器或回调未移除:注册了监听器或回调但未及时移除,导致对象无法被回收。
  • 内部类持有外部类引用:非静态内部类会隐式持有外部类的引用,如果内部类对象未释放,外部类对象也无法释放。
  • 缓存未清理:缓存中的对象未被及时清理,导致内存占用不断增加。
如何避免内存泄露:
  • 及时释放不再使用的资源。
  • 使用弱引用(WeakReference)或软引用(SoftReference)来管理缓存。
  • 避免滥用静态变量。
  • 使用工具(如 Java VisualVMEclipse MAT)检测内存泄露。

2. 内存溢出(Out Of Memory, OOM)

内存溢出是指程序在申请内存时,没有足够的内存空间供其使用。通常是因为内存泄露累积、程序本身需要的内存超过了 JVM 分配的最大内存限制,或者内存分配不合理。

内存溢出的常见原因:
  • 内存泄露:内存泄露累积到一定程度会导致内存溢出。
  • 大对象或大数组:一次性申请过大的内存空间(如加载大文件到内存)。
  • JVM 内存设置过小:JVM 堆内存(-Xmx)设置过小,无法满足程序需求。
  • 过多的线程:每个线程都会占用一定的栈空间,线程过多可能导致栈内存溢出。
如何避免内存溢出:
  • 合理设置 JVM 内存参数(如 -Xmx-Xms)。
  • 优化代码,避免一次性加载过多数据到内存。
  • 使用缓存时设置合理的缓存大小和过期策略。
  • 定期检查并修复内存泄露问题。

内存泄露与内存溢出的关系

  • 内存泄露是内存溢出的一个可能原因,但不是唯一原因。
  • 内存泄露会导致可用内存逐渐减少,最终可能引发内存溢出。
  • 内存溢出可能是由于内存泄露,也可能是由于程序本身需要的内存超过了 JVM 的限制。

示例代码

内存泄露示例:
public class MemoryLeakExample {private static List<Object> list = new ArrayList<>();public void addToCache(Object obj) {list.add(obj); // 对象被添加到静态集合中,无法被回收}
}
内存溢出示例:
public class OutOfMemoryExample {public static void main(String[] args) {List<byte[]> list = new ArrayList<>();while (true) {list.add(new byte[1024 * 1024]); // 不断申请内存,最终导致 OOM}}
}

总结

  • 内存泄露:对象不再使用但未被回收,导致内存浪费。
  • 内存溢出:程序申请的内存超过了可用内存,导致程序崩溃。
  • 解决内存问题的关键是合理管理内存,避免内存泄露,并优化内存使用。
维度内存泄漏内存溢出
本质对象无法回收,内存被无效占用。内存不足,无法分配新对象。
触发条件长期运行后逐渐积累。可能由内存泄漏引发,也可能瞬间发生(如加载超大文件)。
表现程序性能逐渐下降,最终可能触发内存溢出。直接抛出OutOfMemoryError,程序崩溃。
解决方案修复代码逻辑(如及时释放资源、清除集合)。增加JVM内存或优化程序(如分页查询、减少对象创建)。

2.java 中数据在内存中是如何存储的?

在Java中,数据在内存中的存储方式取决于数据类型和变量的声明方式。基本数据类型(如int、double、boolean等)直接存储在栈内存(Stack Memory)中,而对象的引用则存储在栈内存中,而对象本身存储在堆内存(Heap Memory)中

在 Java 中,数据在内存中的存储方式主要分为以下几个部分:栈(Stack)堆(Heap)方法区(Method Area)本地方法栈(Native Method Stack)。不同的数据类型和对象在内存中的存储位置和方式有所不同。


1. 栈(Stack)

栈内存用于存储局部变量方法参数方法调用的上下文。它的特点是:

  • 速度快:栈内存的分配和回收速度非常快。
  • 生命周期短:栈内存中的数据随着方法的调用而创建,随着方法的结束而销毁。
  • 线程私有:每个线程都有自己的栈内存。
栈中存储的内容:
  • 基本数据类型:如 intfloatboolean 等,直接存储值。
  • 对象引用:对象的引用(地址)存储在栈中,而对象本身存储在堆中。
  • 方法调用栈帧:每个方法调用会创建一个栈帧,存储局部变量、操作数栈、动态链接和方法返回地址。
示例:
public void exampleMethod() {int a = 10; // 基本数据类型,存储在栈中String str = "Hello"; // 对象引用存储在栈中,对象本身在堆中
}

2. 堆(Heap)

堆内存用于存储对象实例数组。它的特点是:

  • 生命周期长:堆中的对象由垃圾回收器(GC)管理,不需要手动释放。
  • 线程共享:堆内存是所有线程共享的。
  • 速度较慢:堆内存的分配和回收速度相对较慢。
堆中存储的内容:
  • 对象实例:通过 new 关键字创建的对象。
  • 数组:无论是基本数据类型数组还是对象数组。
  • 字符串常量池:字符串常量(如 String str = "Hello")存储在堆中的字符串常量池。
示例:
public void exampleMethod() {Object obj = new Object(); // 对象实例存储在堆中int[] arr = new int[10]; // 数组存储在堆中
}

3. 方法区(Method Area)

方法区是堆的一个逻辑部分,用于存储:

  • 类信息:类的元数据(如类名、方法信息、字段信息等)。
  • 静态变量static 修饰的变量。
  • 常量池:编译期生成的字面量和符号引用。
  • 运行时常量池:类加载后,常量池中的内容会被加载到运行时常量池。
示例:
public class Example {public static int staticVar = 10; // 静态变量存储在方法区public final String constant = "Constant"; // 常量存储在方法区的常量池
}

4. 本地方法栈(Native Method Stack)

本地方法栈用于支持 Native 方法(用 native 关键字修饰的方法,通常是用 C/C++ 实现的)。它的特点是:

  • 与栈类似,但专门用于 Native 方法的调用。

5. 程序计数器(Program Counter Register)

程序计数器是一个很小的内存区域,用于存储当前线程执行的字节码指令地址。每个线程都有自己的程序计数器。


数据存储的总结

数据类型存储位置说明
基本数据类型直接存储值。
对象引用存储对象的地址,对象本身在堆中。
对象实例通过 new 创建的对象。
数组无论是基本数据类型数组还是对象数组。
静态变量方法区static 修饰的变量。
常量方法区的常量池final 修饰的常量。
类信息方法区类的元数据(如方法、字段信息等)。
本地方法本地方法栈native 方法的相关数据。

示例代码分析

public class MemoryExample {private static int staticVar = 10; // 静态变量,存储在方法区private int instanceVar = 20; // 实例变量,存储在堆中public void method() {int localVar = 30; // 局部变量,存储在栈中Object obj = new Object(); // 对象引用在栈中,对象实例在堆中}
}

总结

  • :存储局部变量、方法参数和对象引用。
  • :存储对象实例和数组。
  • 方法区:存储类信息、静态变量和常量池。
  • 本地方法栈:存储 Native 方法的调用信息。

理解 Java 内存模型对于编写高效、稳定的程序非常重要,尤其是在处理内存泄露和性能优化时。

3.Error 和 Exception 的区别?

Error 和 Exception 都有一个共同的根类是 Throwable 类。
Error 是系统中的错误,程序员是不能改变的和处理的,一般是指与虚拟机相关的问题,对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。因此我们编写程序时不需要关心这类错误。

Exception,也就是我们经常见到的一些异常情况,表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

在 Java 中,ErrorException 都是 Throwable 类的子类,但它们代表了不同类型的异常情况,用途和处理方式也有所不同。


1. Error

Error 表示程序无法处理的严重问题,通常与虚拟机(JVM)或系统资源相关。Error不可检查的异常(Unchecked Exception),程序通常无法恢复或处理这些问题。

Error 的特点:
  • 严重性:表示系统级别的错误,通常是致命的。
  • 不可恢复:程序无法从 Error 中恢复。
  • 不需要捕获:通常不需要在代码中显式捕获或处理 Error
常见的 Error 类型:
  • OutOfMemoryError:内存不足错误,通常是由于堆内存耗尽。
  • StackOverflowError:栈溢出错误,通常是由于递归调用过深。
  • NoClassDefFoundError:类定义未找到错误,通常是由于类加载失败。
  • VirtualMachineError:虚拟机错误,表示 JVM 出现了严重问题。
示例:
public class ErrorExample {public static void main(String[] args) {recursiveMethod(); // 递归调用导致栈溢出}public static void recursiveMethod() {recursiveMethod(); // 无限递归,最终抛出 StackOverflowError}
}

2. Exception

Exception 表示程序可以处理的异常情况,通常是程序逻辑或外部环境导致的。Exception 分为两类:

  1. 检查型异常(Checked Exception):必须在代码中显式处理(捕获或抛出)。
  2. 非检查型异常(Unchecked Exception):通常是程序逻辑错误,不需要显式处理。
Exception 的特点:
  • 可恢复性:程序通常可以从 Exception 中恢复。
  • 需要处理:检查型异常必须在代码中显式处理。
  • 分类
    • 检查型异常:如 IOExceptionSQLException
    • 非检查型异常:如 NullPointerExceptionArithmeticException
常见的 Exception 类型:
  • 检查型异常
    • IOException:输入输出异常。
    • SQLException:数据库操作异常。
    • ClassNotFoundException:类未找到异常。
  • 非检查型异常
    • NullPointerException:空指针异常。
    • ArithmeticException:算术异常(如除以零)。
    • ArrayIndexOutOfBoundsException:数组越界异常。
示例:
public class ExceptionExample {public static void main(String[] args) {try {int result = 10 / 0; // 抛出 ArithmeticException} catch (ArithmeticException e) {System.out.println("捕获到算术异常: " + e.getMessage());}}
}

Error 和 Exception 的区别

特性ErrorException
类型不可检查的异常(Unchecked)检查型异常(Checked)和非检查型异常(Unchecked)
严重性严重,通常是致命的可恢复,通常是程序逻辑或外部环境问题
处理方式通常不需要捕获或处理检查型异常必须显式处理,非检查型异常可选处理
来源通常与 JVM 或系统资源相关通常与程序逻辑或外部环境相关
示例OutOfMemoryErrorStackOverflowErrorIOExceptionNullPointerException

总结

  • Error:表示系统级别的严重问题,程序通常无法恢复,不需要显式处理。
  • Exception:表示程序可以处理的异常情况,分为检查型异常和非检查型异常,通常需要显式处理。

在实际开发中,应重点关注 Exception 的处理,而对于 Error,通常需要从系统或 JVM 层面进行优化和调整。

4.常见的异常有哪些?

java.lang.RuntimeException: 运行时异常

ClassCastException: 类类型转换异常,当试图将对象强制转换为不是实例的子类时,抛出该异常;

ArrayIndexOutOfBoundsException: 数组下标越界异常,当你使用不合法的索引访问数组时会抛出该异常;

NullPointerException: 空指针异常,通过 null 进行方法和属性调用会抛出该异常;

ArithmeticException: 算术运算异常,除数为 0,抛出该异常;

NumberFormatException: 数字转换异常,当试图将一个 String 转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常;

InputMismatchException: 输入不匹配异常,输入的值数据类型与设置的值数据类型不能匹配。

java 编译时异常:
SQLException: SQL 异常,提供有关数据库访问错误或其他错误的信息的异常;

IOExeption: 输入输出异常,表示发送了某种 I/O 异常的信号。FileNotFoundException: 文件找不到异常,通常是两种情况:1、系统找不到指定的路径 2、拒绝访问(指定的是目录时,就会报拒绝访问异常)

EOFException: 文件已结束异常,抛出 EOFException 一定是因为连接断了还在继续read;

java.lang.ClassNotFoundException: 类找不到异常,当我们通过配置文件去查找一个类的时候,如果配置路径写错,就会抛出该异常,比如:web.xml 文件中根本就不存在该类的配置或者配置的路径写错;

在编程和系统运行中,常见的异常类型包括:

  1. 空指针异常(NullPointerException)

    • 尝试访问或操作一个空对象。
  2. 数组越界异常(ArrayIndexOutOfBoundsException)

    • 访问数组时超出其范围。
  3. 类型转换异常(ClassCastException)

    • 试图将对象强制转换为不兼容的类型。
  4. 算术异常(ArithmeticException)

    • 如除零错误。
  5. 输入输出异常(IOException)

    • 文件读写或网络通信失败。
  6. 文件未找到异常(FileNotFoundException)

    • 尝试访问不存在的文件。
  7. 非法参数异常(IllegalArgumentException)

    • 方法接收到非法参数。
  8. 非法状态异常(IllegalStateException)

    • 对象处于不适合执行操作的状态。
  9. 并发修改异常(ConcurrentModificationException)

    • 在迭代集合时修改集合内容。
  10. 栈溢出异常(StackOverflowError)

    • 递归调用过深导致栈空间耗尽。
  11. 内存溢出异常(OutOfMemoryError)

    • 内存不足,无法分配对象。
  12. 类未找到异常(ClassNotFoundException)

    • 尝试加载不存在的类。
  13. 未实现异常(UnsupportedOperationException)

    • 调用未实现的操作。
  14. 安全异常(SecurityException)

    • 违反安全限制的操作。
  15. 超时异常(TimeoutException)

    • 操作在规定时间内未完成。
  16. 中断异常(InterruptedException)

    • 线程在等待或睡眠时被中断。
  17. 格式异常(NumberFormatException)

    • 字符串转换为数字时格式不正确。
  18. 未找到资源异常(NoSuchElementException)

    • 尝试访问不存在的元素。
  19. 断言错误(AssertionError)

    • 断言条件不成立。
  20. 虚拟机错误(VirtualMachineError)

    • 虚拟机出现严重问题。

这些异常通常通过try-catch块捕获和处理,以确保程序稳定运行。

5.请说一下递归的概念?

递归是计算机的重要概念,就是在过程或函数里调用自身,以达到能使程序更加简洁、清晰

递归是一种在函数定义中使用函数自身的方法。在计算机科学中,递归算法是一种直接或者间接调用自身函数或者方法的算法。递归通常用于解决可以分解为相似的子问题的问题。递归方法的核心在于将问题分解成更小的、更容易解决的子问题,直到这些子问题足够小以至于可以直接解决。

递归的两个关键要素是:

  1. 基准情形(Base Case):这是递归的终止条件。在基准情形下,递归不再进行,而是返回一个确定的值。没有基准情形或者基准情形设置不当,递归将无限进行下去,导致栈溢出错误。

  2. 递归情形(Recursive Case):这是递归的主体部分,它将问题分解成更小的子问题,并调用自身来解决这些子问题。每一次递归调用都应该使问题向基准情形靠近。

递归的一个经典例子是计算阶乘。阶乘函数定义为:

  • 基准情形:0! = 1
  • 递归情形:n! = n * (n-1)!

用伪代码表示递归计算阶乘的函数如下:

function factorial(n):if n == 0:return 1else:return n * factorial(n - 1)

在这个例子中,factorial函数在n不为0时调用自身,每次调用时n的值减1,直到n为0时递归停止,开始返回计算结果。

递归的优点是代码简洁且易于理解,尤其适用于处理如树形结构、分治算法、动态规划等问题。然而,递归也有缺点,比如可能会导致大量的函数调用,消耗栈空间,以及可能引起栈溢出。在某些情况下,递归可以被迭代(循环)所替代,以减少资源消耗。

6.try…catch…finally的作用?

try 块中放可能发生异常的代码。
catch 块用于捕获并处理一个特定的异常,catch 块可以有多个;
finally 块无论异常是否发生,异常是否匹配被处理,都会执行,主要做一些清理工作, 比如释放资源;
try 必须有,catch 和 finally 都是可选的;但是 try 不能单独存在,至少要和 catch 或finally 其中一个结合使用;

try...catch...finally 是许多编程语言中用于异常处理的结构。它的作用是在程序中捕获和处理异常,确保代码的健壮性和稳定性。以下是每个部分的作用:

1. try

  • 作用:包裹可能会抛出异常的代码。
  • 说明:在 try 块中,程序会正常执行代码。如果代码执行过程中发生异常,程序会立即跳转到 catch 块处理异常;如果没有异常,catch 块会被跳过。

2. catch

  • 作用:捕获并处理 try 块中抛出的异常。
  • 说明catch 块可以捕获特定类型的异常(如 NullPointerExceptionIOException 等),并定义处理逻辑。可以有一个或多个 catch 块,用于处理不同类型的异常。
  • 注意:如果 try 块中没有抛出异常,catch 块不会执行。

3. finally

  • 作用:无论是否发生异常,finally 块中的代码都会执行。
  • 说明finally 块通常用于释放资源、关闭文件、断开连接等清理操作,确保这些操作无论程序是否发生异常都会执行。
  • 注意:即使 trycatch 块中有 return 语句,finally 块仍然会执行。

执行顺序

  1. 执行 try 块中的代码。
  2. 如果 try 块中发生异常,跳转到匹配的 catch 块处理异常。
  3. 无论是否发生异常,最终都会执行 finally 块。

示例代码

try {// 可能会抛出异常的代码int result = 10 / 0; // 这里会抛出 ArithmeticException
} catch (ArithmeticException e) {// 捕获并处理异常System.out.println("捕获到异常: " + e.getMessage());
} finally {// 无论是否发生异常,都会执行的代码System.out.println("finally 块执行");
}

使用场景

  1. 资源释放:如关闭文件、数据库连接、网络连接等。
  2. 异常处理:捕获并处理特定异常,避免程序崩溃。
  3. 清理操作:确保某些操作(如日志记录、状态重置)一定会执行。

注意事项

  1. finally 块中的代码一定会执行,除非程序被强制终止(如 System.exit())。
  2. 如果 catch 块中抛出了新的异常,finally 块仍然会执行,但新异常会覆盖原来的异常。
  3. 尽量避免在 finally 块中使用 return,因为它会覆盖 trycatch 块中的返回值。

通过 try...catch...finally,可以有效地管理异常,确保程序的稳定性和资源的正确释放。

7.try…catch…finally执行顺序问题?

try-catch-finally的执行顺序是:
1、不管有没有出现异常,finally块中的代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的。

try...catch...finally 的执行顺序是固定的,理解它的执行顺序对于正确处理异常和资源管理非常重要。以下是详细的执行顺序规则:


1. 正常情况(无异常)

  • 执行顺序tryfinally
  • 说明
    1. 程序首先执行 try 块中的代码。
    2. 如果 try 块中没有抛出异常,则跳过 catch 块。
    3. 最后执行 finally 块中的代码。

示例

try {System.out.println("try 块执行");
} catch (Exception e) {System.out.println("catch 块执行");
} finally {System.out.println("finally 块执行");
}

输出

try 块执行
finally 块执行

2. 发生异常

  • 执行顺序trycatchfinally
  • 说明
    1. 程序首先执行 try 块中的代码。
    2. 如果 try 块中抛出异常,程序立即跳转到匹配的 catch 块处理异常。
    3. 无论是否捕获到异常,最后都会执行 finally 块中的代码。

示例

try {System.out.println("try 块执行");int result = 10 / 0; // 抛出 ArithmeticException
} catch (ArithmeticException e) {System.out.println("catch 块执行");
} finally {System.out.println("finally 块执行");
}

输出

try 块执行
catch 块执行
finally 块执行

3. trycatch 中有 return

  • 执行顺序trycatchfinallyreturn
  • 说明
    1. 如果 trycatch 块中有 return 语句,程序会先计算 return 的值并暂存。
    2. 然后执行 finally 块中的代码。
    3. 最后返回之前暂存的 return 值。

示例

public static int test() {try {System.out.println("try 块执行");return 1; // 返回值暂存} catch (Exception e) {System.out.println("catch 块执行");return 2; // 返回值暂存} finally {System.out.println("finally 块执行");}
}public static void main(String[] args) {System.out.println("返回值: " + test());
}

输出

try 块执行
finally 块执行
返回值: 1

4. finally 中有 return

  • 执行顺序trycatchfinally(覆盖返回值)
  • 说明
    1. 如果 finally 块中有 return 语句,它会覆盖 trycatch 块中的返回值。
    2. 这种写法不推荐,因为它会掩盖异常和返回值。

示例

public static int test() {try {System.out.println("try 块执行");return 1;} catch (Exception e) {System.out.println("catch 块执行");return 2;} finally {System.out.println("finally 块执行");return 3; // 覆盖返回值}
}public static void main(String[] args) {System.out.println("返回值: " + test());
}

输出

try 块执行
finally 块执行
返回值: 3

5. trycatch 中有 System.exit()

  • 执行顺序trySystem.exit()(程序终止)
  • 说明
    1. 如果 trycatch 块中调用了 System.exit(),程序会立即终止,finally 块不会执行。

示例

try {System.out.println("try 块执行");System.exit(0); // 程序终止
} catch (Exception e) {System.out.println("catch 块执行");
} finally {System.out.println("finally 块执行");
}

输出

try 块执行

总结

  • finally 块一定会执行(除非程序被强制终止,如 System.exit())。
  • return 和异常不会阻止 finally 的执行,但 finally 中的 return 会覆盖之前的返回值。
  • 避免在 finally 中使用 return,以免掩盖异常或返回值。

理解这些规则可以帮助你更好地编写健壮的异常处理代码!

8.throws 和 throw 的区别?

throws 定义在方法的声明中,表示调用该方法可能出现一个或多个异常,由该方法的调
用者来处理;throws 后面跟的是一个或多个异常类型,让它的使用者知道需要捕获的异常的
类型; throws 表示出现异常的一种可能性,并不一定会发生这种异常。
throw 定义在方法内部,表示方法体内,表示抛出异常,由方法体内的语句处理;throw 是
具体向外抛出异常的动作,该语句的后面必须是一个异常对象; 执行 throw 一定抛出了某种
异常。
两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异
常,真正的处理异常由函数的上层调用处理。

throwsthrow 是 Java 中用于异常处理的两个关键字,它们的作用和使用场景完全不同。以下是它们的区别和具体用法:


1. throw

  • 作用:用于在代码中显式抛出一个异常。
  • 使用场景:当程序逻辑中检测到某种错误或异常情况时,可以使用 throw 手动抛出异常。
  • 语法
    throw new ExceptionType("异常信息");
    
  • 特点
    • throw 是一个语句,必须写在方法体内。
    • 抛出的异常可以是 Java 内置的异常类(如 NullPointerExceptionIllegalArgumentException 等),也可以是自定义的异常类。
    • 抛出异常后,程序会立即停止当前方法的执行,并将异常传递给调用者。

示例

public void checkAge(int age) {if (age < 18) {throw new IllegalArgumentException("年龄不能小于18岁");}System.out.println("年龄合法");
}

2. throws

  • 作用:用于在方法声明中指定该方法可能抛出的异常类型。
  • 使用场景:当一个方法内部可能会抛出某种异常,但不想在当前方法中处理时,可以使用 throws 将异常抛给调用者处理。
  • 语法
    返回类型 方法名(参数列表) throws 异常类型1, 异常类型2, ... {// 方法体
    }
    
  • 特点
    • throws 是方法声明的一部分,用于告知调用者该方法可能抛出的异常。
    • 调用者必须处理这些异常(使用 try-catch 或继续向上抛出)。
    • 可以声明多个异常类型,用逗号分隔。

示例

public void readFile(String filePath) throws IOException {FileReader fileReader = new FileReader(filePath);// 读取文件操作
}

3. throwthrows 的区别

特性throwthrows
作用显式抛出一个异常对象。声明方法可能抛出的异常类型。
使用位置方法体内。方法声明中。
异常处理抛出异常后,程序立即停止当前方法执行。仅声明异常,不处理异常。
异常类型必须是一个具体的异常对象。可以是多个异常类型,用逗号分隔。
是否必须可选,根据需要手动抛出异常。如果方法可能抛出受检异常,则必须声明。

4. 结合使用的示例

public class Example {// 方法声明可能抛出 IOExceptionpublic void readFile(String filePath) throws IOException {if (filePath == null) {// 手动抛出异常throw new IllegalArgumentException("文件路径不能为空");}FileReader fileReader = new FileReader(filePath);// 读取文件操作}public static void main(String[] args) {Example example = new Example();try {example.readFile(null); // 调用可能抛出异常的方法} catch (IOException e) {System.out.println("捕获到IO异常: " + e.getMessage());} catch (IllegalArgumentException e) {System.out.println("捕获到非法参数异常: " + e.getMessage());}}
}

5. 总结

  • throw:用于在代码中手动抛出异常。
  • throws:用于在方法声明中指定可能抛出的异常类型。
  • 关系throw 是抛出异常的具体操作,而 throws 是对异常的一种声明和传递。

理解它们的区别和用法,可以帮助你更好地设计异常处理逻辑!

9.final,finally 和 finalize 的比较?

final 修饰类,类不能被继承 final 修饰方法,方法不能被重写,final 修饰变量,变量不能被修改。

finally 是异常语句块的一部分,无论是否有异常,都会被执行。

finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。

finalfinallyfinalize 是 Java 中的三个不同概念,尽管它们在名称上相似,但用途和功能完全不同。以下是它们的比较:

1. final

  • 用途: final 是一个关键字,用于修饰类、方法或变量。
  • 作用:
    • 修饰类: 表示该类不能被继承。
    • 修饰方法: 表示该方法不能被子类重写(override)。
    • 修饰变量: 表示该变量是一个常量,一旦赋值后不能被修改。
  • 示例:
    final class MyClass { // 不能被继承final int myVar = 10; // 常量,不能修改final void myMethod() { // 不能被子类重写System.out.println("This is a final method.");}
    }
    

2. finally

  • 用途: finally 是一个关键字,用于异常处理中的 try-catch 块。
  • 作用: finally 块中的代码无论是否发生异常都会执行,通常用于释放资源或执行清理操作。
  • 示例:
    try {int result = 10 / 0; // 可能抛出异常
    } catch (ArithmeticException e) {System.out.println("Exception caught: " + e.getMessage());
    } finally {System.out.println("This will always be executed.");
    }
    

3. finalize

  • 用途: finalizeObject 类中的一个方法,用于垃圾回收。
  • 作用: 在对象被垃圾回收器回收之前,finalize 方法会被调用,通常用于释放非内存资源(如文件句柄、网络连接等)。
  • 注意: finalize 方法不保证一定会被执行,且不推荐依赖它来释放资源,因为垃圾回收的时间是不确定的。
  • 示例:
    class MyClass {@Overrideprotected void finalize() throws Throwable {try {System.out.println("Finalize method called.");} finally {super.finalize();}}
    }
    

总结

  • final: 用于修饰类、方法或变量,表示不可继承、不可重写或不可修改。
  • finally: 用于异常处理,确保某段代码无论是否发生异常都会执行。
  • finalize: 用于垃圾回收,在对象被回收前执行清理操作,但不推荐依赖。

这三者在 Java 中扮演不同的角色,理解它们的区别有助于编写更健壮和高效的代码。

10.进程和线程的区别?

1、线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
2、一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
3、进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见;
4、调度和切换:线程上下文切换比进程上下文切换要快得多;

进程(Process)和线程(Thread)是操作系统中的两个核心概念,它们都是程序执行的基本单位,但在资源管理、调度和通信等方面存在显著区别。以下是它们的详细比较:


1. 定义

  • 进程:

    • 进程是操作系统分配资源的基本单位,是程序的一次执行过程。
    • 每个进程都有独立的内存空间、文件描述符、系统资源等。
    • 进程之间相互隔离,一个进程崩溃不会直接影响其他进程。
  • 线程:

    • 线程是进程中的一个执行单元,是 CPU 调度的基本单位。
    • 线程共享进程的内存空间和资源,但每个线程有自己的栈和程序计数器。
    • 线程之间可以直接通信,但需要同步机制来避免资源竞争。

2. 资源分配

  • 进程:

    • 每个进程都有独立的内存空间(代码段、数据段、堆栈等)。
    • 进程之间的资源是隔离的,通信需要通过进程间通信(IPC)机制,如管道、消息队列、共享内存等。
  • 线程:

    • 线程共享进程的内存空间和资源(如堆、全局变量等)。
    • 线程之间的通信更高效,因为它们可以直接读写共享数据。

3. 创建和销毁的开销

  • 进程:

    • 创建和销毁进程的开销较大,因为需要分配和回收独立的内存空间和资源。
    • 进程切换(上下文切换)的开销也较大,因为需要保存和恢复整个进程的状态。
  • 线程:

    • 创建和销毁线程的开销较小,因为线程共享进程的资源。
    • 线程切换的开销也较小,因为只需要保存和恢复线程的栈和程序计数器。

4. 独立性

  • 进程:

    • 进程之间相互独立,一个进程崩溃不会影响其他进程。
    • 进程之间的数据共享需要通过 IPC 机制。
  • 线程:

    • 线程之间共享进程的资源,一个线程崩溃可能导致整个进程崩溃。
    • 线程之间的数据共享更直接,但需要同步机制(如锁、信号量)来避免竞争条件。

5. 并发性

  • 进程:

    • 进程之间可以并发执行,但进程切换的开销较大。
    • 适合需要高隔离性和安全性的场景。
  • 线程:

    • 线程之间可以更高效地并发执行,因为线程切换的开销较小。
    • 适合需要高效资源共享和通信的场景。

6. 应用场景

  • 进程:

    • 适合需要高隔离性和安全性的任务,如浏览器中的多个标签页、操作系统的多个应用程序。
    • 适合分布式计算和多机协作的场景。
  • 线程:

    • 适合需要高效资源共享和通信的任务,如 Web 服务器处理多个客户端请求、图形界面程序中的多任务处理。
    • 适合单机多核 CPU 的并行计算。

7. 示例

  • 进程:

    • 在操作系统中,打开多个应用程序(如浏览器、文本编辑器)会创建多个进程。
    • 每个进程有独立的内存空间,互不干扰。
  • 线程:

    • 在一个浏览器进程中,可能有多个线程分别负责渲染页面、处理网络请求、运行 JavaScript 等。
    • 这些线程共享浏览器的内存空间,可以高效通信。

总结对比表

特性进程线程
定义资源分配的基本单位CPU 调度的基本单位
资源分配独立的内存空间和资源共享进程的内存空间和资源
创建/销毁开销较大较小
切换开销较大较小
独立性进程之间相互独立线程之间共享资源
通信机制进程间通信(IPC)直接共享内存
崩溃影响一个进程崩溃不影响其他进程一个线程崩溃可能导致整个进程崩溃
适用场景高隔离性、安全性要求高的任务高效资源共享、通信要求高的任务

选择进程还是线程?

  • 如果需要高隔离性和安全性,选择进程
  • 如果需要高效资源共享和通信,选择线程
  • 在现代多核 CPU 系统中,通常结合使用进程和线程(如多进程 + 多线程)以实现更高的并发性和性能。

11.并行和并发?

并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。
并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流
进行,由于时间间隔较短,使人感觉两个任务都在运行

并行(Parallelism)并发(Concurrency) 是两个与多任务处理相关的概念,尽管它们经常被混用,但它们在含义和实现方式上有本质区别。以下是它们的详细比较:


1. 定义

  • 并发(Concurrency):

    • 并发是指多个任务在同一时间段内交替执行,从宏观上看似乎是同时进行的,但实际上可能是通过快速切换任务来实现的。
    • 并发更关注任务的分解和调度,适用于单核或多核系统。
  • 并行(Parallelism):

    • 并行是指多个任务在同一时刻真正同时执行,通常需要多核或多处理器的硬件支持。
    • 并行更关注任务的执行效率,适用于多核系统。

2. 核心区别

  • 并发:

    • 强调任务的交替执行,通过时间片轮转或任务调度实现。
    • 适用于任务之间存在依赖或需要共享资源的场景。
    • 目标是提高系统的响应性和资源利用率。
  • 并行:

    • 强调任务的同时执行,通过多核或多处理器实现。
    • 适用于任务之间独立且可以同时执行的场景。
    • 目标是提高系统的计算效率和吞吐量。

3. 实现方式

  • 并发:

    • 在单核 CPU 上,通过操作系统的任务调度机制(如时间片轮转)实现并发。
    • 在多核 CPU 上,可以结合并行实现更高效的并发。
    • 常见的并发模型:多线程、事件驱动、协程等。
  • 并行:

    • 需要多核 CPU 或多处理器的硬件支持。
    • 常见的并行模型:多进程、多线程、GPU 并行计算等。

4. 适用场景

  • 并发:

    • I/O 密集型任务(如文件读写、网络请求)。
    • 需要快速响应的任务(如用户界面、Web 服务器)。
    • 任务之间存在依赖或需要共享资源。
  • 并行:

    • CPU 密集型任务(如科学计算、图像处理)。
    • 任务之间独立且可以同时执行。
    • 需要提高计算效率和吞吐量。

5. 示例

  • 并发:

    • 单核 CPU 上运行多个应用程序(如浏览器、音乐播放器),通过快速切换任务实现并发。
    • Web 服务器同时处理多个客户端请求,通过多线程或事件驱动实现并发。
  • 并行:

    • 多核 CPU 上同时运行多个线程或进程,每个核心执行一个任务。
    • 使用 GPU 进行大规模并行计算(如深度学习训练)。

6. 类比

  • 并发:

    • 类似于一个厨师同时处理多个订单,通过快速切换任务(切菜、煮饭、炒菜)来完成任务。
  • 并行:

    • 类似于多个厨师同时工作,每个厨师负责一个订单,真正同时完成任务。

7. 总结对比表

特性并发(Concurrency)并行(Parallelism)
定义多个任务交替执行,宏观上同时多个任务真正同时执行
核心目标提高响应性和资源利用率提高计算效率和吞吐量
实现方式任务调度、时间片轮转多核 CPU、多处理器
硬件要求单核或多核均可需要多核或多处理器
适用场景I/O 密集型任务、需要快速响应的任务CPU 密集型任务、独立任务
示例单核 CPU 运行多个应用程序多核 CPU 同时运行多个线程

8. 并发与并行的关系

  • 并发和并行可以结合使用:
    • 在多核 CPU 上,可以通过多线程实现并发,同时利用多核实现并行。
    • 例如,一个 Web 服务器可以使用多线程(并发)处理多个请求,同时利用多核 CPU 实现并行计算。

9. 编程模型

  • 并发编程:

    • 多线程(如 Java 的 Thread、Python 的 threading)。
    • 事件驱动(如 Node.js 的异步 I/O)。
    • 协程(如 Python 的 asyncio、Go 的 goroutine)。
  • 并行编程:

    • 多进程(如 Python 的 multiprocessing)。
    • 多线程(如 Java 的 Thread、C++ 的 std::thread)。
    • GPU 并行计算(如 CUDA、OpenCL)。

总结

  • 并发 是逻辑上的同时执行,适用于任务调度和资源共享。
  • 并行 是物理上的同时执行,适用于提高计算效率。
  • 在实际应用中,通常需要结合并发和并行来实现高效的多任务处理。

12.JVM 的启动是多线程的吗

多线程的。JVM 启动其实至少有三个线程:main 主线程,gc 垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程

是的,JVM 的启动是多线程的。以下是几个关键点:

  1. 主线程:负责执行 main 方法,启动应用程序。
  2. 后台线程:JVM 启动时会创建多个后台线程,用于垃圾回收、JIT 编译等任务。
  3. 系统线程:包括处理信号、终结器线程等,用于支持 JVM 运行。

主要后台线程

  • GC 线程:负责垃圾回收。
  • JIT 编译线程:将热点代码编译为本地机器码。
  • Finalizer 线程:调用对象的 finalize 方法。
  • Reference Handler 线程:处理引用对象(如软引用、弱引用)。

总结

JVM 启动时是多线程的,除了主线程外,还有多个后台线程支持 JVM 的运行和管理。

13.多线程的创建方式?

JDK5 之前:
继承 Thread 类
实现 Runnable 接口
JDK5 之后:
使用 Callable 接口创建线程
通过线程池创建线程

在 Java 中,创建多线程的方式主要有以下几种:


1. 继承 Thread

通过继承 Thread 类并重写 run() 方法来实现多线程。

class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动线程}
}

特点

  • 简单易用。
  • 由于 Java 是单继承,继承 Thread 类后会限制扩展其他类。

2. 实现 Runnable 接口

通过实现 Runnable 接口并重写 run() 方法,然后将 Runnable 实例传递给 Thread 对象。

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Thread is running: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start(); // 启动线程}
}

特点

  • 更灵活,因为可以实现多个接口。
  • 适合资源共享的场景(多个线程可以共享同一个 Runnable 实例)。

3. 实现 Callable 接口

通过实现 Callable 接口,可以创建有返回值的线程,通常与 FutureTask 或线程池一起使用。

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "Thread is running: " + Thread.currentThread().getName();}
}public class Main {public static void main(String[] args) throws Exception {FutureTask<String> futureTask = new FutureTask<>(new MyCallable());Thread thread = new Thread(futureTask);thread.start(); // 启动线程System.out.println(futureTask.get()); // 获取线程返回值}
}

特点

  • 可以返回结果。
  • 可以抛出异常。

4. 使用线程池

通过线程池(如 ExecutorService)管理线程,避免频繁创建和销毁线程的开销。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Main {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);executor.submit(() -> {System.out.println("Thread is running: " + Thread.currentThread().getName());});executor.shutdown(); // 关闭线程池}
}

特点

  • 高效管理线程资源。
  • 适合需要大量线程的场景。

5. 使用 Lambda 表达式(Java 8+)

结合 RunnableCallable,可以使用 Lambda 表达式简化代码。

public class Main {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("Thread is running: " + Thread.currentThread().getName());});thread.start();}
}

特点

  • 代码简洁。
  • 适合简单的线程任务。

总结

方式特点
继承 Thread简单,但单继承限制扩展性。
实现 Runnable 接口灵活,适合资源共享。
实现 Callable 接口支持返回值和异常处理。
使用线程池高效管理线程,适合高并发场景。
使用 Lambda 表达式代码简洁,适合简单任务。

根据具体需求选择合适的方式即可。

14.继承Thread类和实现Runnable接口的对比?

查看源码的区别:
a、继承 Thread : 由于子类重写了 Thread 类的 run(), 当调用 start()时, 直接
找子类的 run()方法。
b、实现 Runnable : 构造函数中传入了 Runnable 的引用, 成员变量记住了它,
start()调用 run()方法时内部判断成员变量 Runnable 的引用是否为空, 不为空编译时看的
是 Runnable 的 run(),运行时执行的是子类的 run()方法(也就是实现了 Runnable 接口并重
写了 run()方法的类中的 run()方法)。
继承 Thread:
好处是:可以直接使用 Thread 类中的方法,代码简单。
弊端是:如果已经有了父类,就不能用这种方法。
实现 Runnable 接口(推荐):
好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口, 而且接口是可以多实现的,避免了单继承的局限性。多个线程可以共享同一个接口实现类的
对象,非常适合多个相同线程来处理同一份资源。
弊端是:不能直接使用 Thread 中的方法需要先获取到线程对象后,才能得到 Thread
的方法,代码复杂

继承 Thread 类和实现 Runnable 接口是 Java 中创建多线程的两种主要方式,它们各有优缺点。以下是它们的详细对比:


1. 继承 Thread

实现方式

通过继承 Thread 类并重写 run() 方法。

class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动线程}
}
优点
  • 简单易用:直接继承 Thread 类,代码直观。
  • 直接调用线程方法:可以直接调用 Thread 类的方法,如 start()sleep() 等。
缺点
  • 单继承限制:Java 是单继承语言,继承 Thread 类后无法再继承其他类,限制了类的扩展性。
  • 耦合性高:线程逻辑与线程类绑定,不利于代码复用。

2. 实现 Runnable 接口

实现方式

通过实现 Runnable 接口并重写 run() 方法,然后将 Runnable 实例传递给 Thread 对象。

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Thread is running: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start(); // 启动线程}
}
优点
  • 灵活性高:可以实现多个接口,扩展性更强。
  • 资源共享:多个线程可以共享同一个 Runnable 实例,适合资源共享的场景。
  • 解耦:线程逻辑与线程类分离,代码更清晰,易于维护。
缺点
  • 稍复杂:需要额外创建 Thread 对象来启动线程。

对比总结

特性继承 Thread实现 Runnable 接口
继承限制单继承,无法继承其他类可以实现多个接口,扩展性强
资源共享不适合资源共享适合资源共享(多个线程共享一个实例)
代码复用线程逻辑与线程类绑定,复用性差线程逻辑与线程类分离,复用性强
耦合性高耦合低耦合
使用场景简单任务,不需要扩展其他类复杂任务,需要资源共享或扩展其他功能
代码简洁性直接调用 Thread 方法,代码简洁需要额外创建 Thread 对象,稍复杂

推荐使用场景

  • 继承 Thread:适合简单的线程任务,且不需要扩展其他类。
  • 实现 Runnable 接口:适合复杂的任务,需要资源共享或扩展其他功能,推荐优先使用。

示例:资源共享场景

实现 Runnable 接口更适合资源共享的场景,例如多个线程操作同一个计数器:

class Counter implements Runnable {private int count = 0;@Overridepublic void run() {for (int i = 0; i < 5; i++) {count++;System.out.println(Thread.currentThread().getName() + ": " + count);}}
}public class Main {public static void main(String[] args) {Counter counter = new Counter();Thread t1 = new Thread(counter);Thread t2 = new Thread(counter);t1.start();t2.start();}

15.什么是守护线程?

java 线程中有两种线程,一种是用户线程(非守护线程),一种是守护线程。

守护线程是一种特殊的线程,它具有陪伴的含义。当进程中不存在非守护线程了,则守护线程自动销毁。

典型的就是垃圾回收线程。当进程中没有非守护线程了,则垃圾回收线程没有存在的必要,自动销毁。

守护线程(Daemon Thread)是 Java 中的一种特殊线程,它的生命周期依赖于非守护线程(用户线程)。当所有非守护线程结束时,守护线程会自动终止,无论它是否执行完毕。


守护线程的特点

  1. 依赖非守护线程

    • 守护线程是为其他线程(非守护线程)提供服务的线程。
    • 当所有非守护线程结束时,JVM 会强制终止所有守护线程。
  2. 不会阻止 JVM 退出

    • 如果只剩下守护线程在运行,JVM 会直接退出,不会等待守护线程完成任务。
  3. 适合后台任务

    • 守护线程通常用于执行后台任务,如垃圾回收、监控、日志记录等。

守护线程的创建

通过 setDaemon(true) 方法将一个线程设置为守护线程。必须在启动线程之前调用,否则会抛出 IllegalThreadStateException

public class DaemonThreadExample {public static void main(String[] args) {Thread daemonThread = new Thread(() -> {while (true) {System.out.println("Daemon thread is running...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});daemonThread.setDaemon(true); // 设置为守护线程daemonThread.start();System.out.println("Main thread is done.");}
}

输出

Main thread is done.
Daemon thread is running...
Daemon thread is running...
...

当主线程(非守护线程)结束时,守护线程也会自动终止。


守护线程 vs 非守护线程

特性守护线程非守护线程(用户线程)
生命周期依赖非守护线程,随非守护线程结束而终止独立运行,不会因其他线程结束而终止
阻止 JVM 退出不会阻止 JVM 退出会阻止 JVM 退出,直到所有非守护线程结束
适用场景后台任务(如垃圾回收、监控)主要业务逻辑
默认类型新创建的线程默认是非守护线程新创建的线程默认是非守护线程
设置方法setDaemon(true)无需设置,默认是非守护线程

注意事项

  1. 不能将正在运行的线程设置为守护线程

    • 必须在调用 start() 方法之前调用 setDaemon(true),否则会抛出 IllegalThreadStateException
  2. 守护线程中的 finally 块不一定会执行

    • 当 JVM 退出时,守护线程会立即终止,finally 块中的代码可能不会执行。
  3. 谨慎使用守护线程

    • 守护线程适合执行不重要的任务,如果任务涉及关键操作(如文件写入、数据保存),应使用非守护线程。

示例:守护线程的应用

守护线程常用于执行后台任务,例如定期清理缓存或监控系统状态:

public class CacheCleaner implements Runnable {@Overridepublic void run() {while (true) {System.out.println("Cleaning cache...");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class Main {public static void main(String[] args) {Thread cleanerThread = new Thread(new CacheCleaner());cleanerThread.setDaemon(true); // 设置为守护线程cleanerThread.start();System.out.println("Main thread is running...");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Main thread is done.");}
}

输出

Main thread is running...
Cleaning cache...
Cleaning cache...
Main thread is done.

当主线程结束后,守护线程也会自动终止。


总结

  • 守护线程是为非守护线程提供服务的后台线程。
  • 当所有非守护线程结束时,守护线程会自动终止。
  • 适合执行不重要的后台任务,但不能用于关键操作。

16.线程的生命周期?

新建状态(New):当一个 Thread 类或其子类的对象被声明并创建时,新生的线程对象处于新建状态。

就绪状态(Runnable):处于新建状态的线程对象被 start()后,线程即进入就绪状态。

运行状态(Running):当就绪状态的线程被操作系统的任务调度机制调度到,此时线程才得以真正执行,即进入到运行状态。

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对 CPU 的使用权,停止执行,此时进入阻塞状态,直到其再次进入到就绪状态,才有机会再次被 CPU 调用以进入到运行状态。

死亡状态(Dead):线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束。

线程的生命周期是指线程从创建到销毁的整个过程。在 Java 中,线程的生命周期可以分为 5 种状态,这些状态定义在 Thread.State 枚举中。以下是线程生命周期的详细说明:


线程的 5 种状态

  1. 新建(NEW)
  2. 就绪(RUNNABLE)
  3. 运行(RUNNING)
  4. 阻塞(BLOCKED)
  5. 等待(WAITING)
  6. 超时等待(TIMED_WAITING)
  7. 终止(TERMINATED)

1. 新建状态(NEW)

  • 线程被创建,但尚未启动。
  • 调用 new Thread() 后,线程处于新建状态。
  • 此时线程还未分配系统资源。
Thread thread = new Thread();
System.out.println(thread.getState()); // 输出: NEW

2. 就绪状态(RUNNABLE)

  • 线程已经启动,等待 CPU 调度执行。
  • 调用 start() 方法后,线程进入就绪状态。
  • 此时线程已经分配了系统资源,但还未开始执行。
thread.start();
System.out.println(thread.getState()); // 输出: RUNNABLE

3. 运行状态(RUNNING)

  • 线程获得 CPU 时间片,开始执行 run() 方法。
  • 运行状态是 RUNNABLE 状态的一个子状态,JVM 没有明确区分就绪和运行状态。

4. 阻塞状态(BLOCKED)

  • 线程因为某些原因暂时停止执行,但不会释放锁。
  • 常见场景:
    • 等待进入 synchronized 代码块或方法。
    • 等待 I/O 操作完成。
synchronized (lock) {// 其他线程尝试进入时会被阻塞
}

5. 等待状态(WAITING)

  • 线程无限期等待,直到被其他线程显式唤醒。
  • 常见方法:
    • Object.wait():等待其他线程调用 notify()notifyAll()
    • Thread.join():等待目标线程执行完毕。
synchronized (lock) {lock.wait(); // 线程进入等待状态
}

6. 超时等待状态(TIMED_WAITING)

  • 线程等待一段时间,超时后自动唤醒。
  • 常见方法:
    • Thread.sleep(long millis):线程休眠指定时间。
    • Object.wait(long timeout):等待指定时间。
    • Thread.join(long millis):等待目标线程指定时间。
Thread.sleep(1000); // 线程进入超时等待状态

7. 终止状态(TERMINATED)

  • 线程执行完毕或异常退出。
  • 线程进入终止状态后,无法再次启动。
thread.start();
thread.join(); // 等待线程执行完毕
System.out.println(thread.getState()); // 输出: TERMINATED

线程状态转换图

以下是线程状态之间的转换关系:

NEW → RUNNABLE → RUNNING → TERMINATED↓BLOCKED↓WAITING↓TIMED_WAITING

示例代码:观察线程状态

public class ThreadLifecycleExample {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {try {Thread.sleep(1000); // 进入 TIMED_WAITING 状态} catch (InterruptedException e) {e.printStackTrace();}});System.out.println("After creation: " + thread.getState()); // NEWthread.start();System.out.println("After start: " + thread.getState()); // RUNNABLEThread.sleep(500);System.out.println("During sleep: " + thread.getState()); // TIMED_WAITINGthread.join();System.out.println("After completion: " + thread.getState()); // TERMINATED}
}

输出

After creation: NEW
After start: RUNNABLE
During sleep: TIMED_WAITING
After completion: TERMINATED

总结

状态描述
NEW线程被创建,但未启动。
RUNNABLE线程已启动,等待 CPU 调度。
BLOCKED线程被阻塞,等待获取锁。
WAITING线程无限期等待,直到被唤醒。
TIMED_WAITING线程等待指定时间,超时后自动唤醒。
TERMINATED线程执行完毕或异常退出。

理解线程的生命周期对于编写高效、稳定的多线程程序至关重要。

17.阻塞状态的分类?

根据阻塞产生的原因不同,阻塞状态又可以分为三种:

1.等待阻塞:运行状态中的线程执行 wait()方法,使本线程进入到等待阻塞状态;

2.同步阻塞:线程在获取 synchronized 同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

3.其他阻塞:通过调用线程的 sleep()或 join()或发出了 I/O 请求时,线程会进入到阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入就绪状态。


在 Java 中,线程的阻塞状态主要可以分为以下几种类型:

1. 等待阻塞(Waiting)

线程在等待某个条件发生时会进入等待阻塞状态。这种状态下的线程不会占用 CPU 资源,直到被其他线程唤醒。常见的等待阻塞情况包括:

  • Object.wait():线程调用对象的 wait() 方法后,进入等待状态,直到其他线程调用同一对象的 notify()notifyAll() 方法。
  • Thread.join():线程调用另一个线程的 join() 方法,等待该线程完成后再继续执行。
  • LockSupport.park():使用 LockSupport 类的 park() 方法使线程进入等待状态。

2. 阻塞阻塞(Blocked)

当线程试图获取一个已经被其他线程持有的锁时,会进入阻塞阻塞状态。这种状态下的线程会被挂起,直到能够获取到锁。常见的情况包括:

  • 同步方法:当一个线程进入一个同步方法时,其他线程如果也想进入这个方法,就会被阻塞,直到第一个线程释放锁。
  • 同步块:在 synchronized 块中,如果一个线程已经持有了锁,其他线程尝试进入同一块代码时会被阻塞。

3. 定时阻塞(Timed Waiting)

线程在等待某个条件发生时,可以设置一个超时时间。如果在超时时间内条件没有满足,线程会自动返回。常见的定时阻塞情况包括:

  • Thread.sleep(milliseconds):线程进入睡眠状态,指定的时间后自动唤醒。
  • Object.wait(milliseconds):线程在等待状态中,指定的时间后自动返回。
  • Thread.join(milliseconds):线程等待另一个线程完成,指定的时间后自动返回。
  • LockSupport.parkNanos(nanos)LockSupport.parkUntil(Deadline):使用 LockSupport 类的定时等待方法。

总结

在 Java 中,线程的阻塞状态可以分为等待阻塞、阻塞阻塞和定时阻塞。每种状态都有其特定的场景和使用方法,理解这些状态有助于更好地管理和优化多线程程序的性能。

18.什么线程安全问题?

多线程并发操作同一数据时,会造成操作的不完整性,会破坏数据;

问题的原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。

多个线程操作同一数据,如果当前线程 a 没有操作完该数据,其他线程参与进来执行,那么就会导致数据的错误,这就是线程安全问题;一定要明确的是:同一数据

解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。

使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作;


线程安全问题主要指在多线程环境中,多个线程同时访问共享资源(如变量、数据结构等)时,可能导致数据不一致或程序行为异常的情况。以下是一些常见的线程安全问题:

  1. 竞态条件(Race Condition)
    当两个或多个线程同时访问和修改共享数据时,最终的结果依赖于线程执行的顺序。如果没有适当的同步机制,可能会导致数据不一致。

  2. 死锁(Deadlock)
    当两个或多个线程相互等待对方释放资源时,导致所有线程都无法继续执行。死锁通常发生在多个线程需要获取多个资源时。

  3. 活锁(Livelock)
    线程在不断地改变状态以响应其他线程的状态变化,但没有实际进展。虽然线程没有被阻塞,但它们仍然无法完成任务。

  4. 饥饿(Starvation)
    某些线程无法获得所需的资源,导致它们无法执行。饥饿通常发生在资源分配不均的情况下。

  5. 数据不一致(Data Inconsistency)
    当多个线程同时读取和写入共享数据时,可能会导致数据处于不一致的状态。例如,一个线程可能在另一个线程更新数据时读取了旧值。

为了解决这些问题,通常会使用同步机制,如互斥锁(Mutex)、信号量(Semaphore)、读写锁(Read-Write Lock)等,来确保在同一时刻只有一个线程可以访问共享资源。

19.什么是线程同步?

线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下个线程在使用。

每个对象都有一把锁;队列 + 锁 就是用来保证多线程安全性;


线程同步是指在多线程环境中,确保多个线程在访问共享资源时不会发生冲突或数据不一致的机制。由于多个线程可以同时执行,若不加以控制,可能会导致数据竞争、死锁等问题,从而影响程序的正确性和稳定性。

线程同步的常见方法包括:

  1. 互斥锁(Mutex):通过锁机制,确保同一时间只有一个线程可以访问共享资源。
  2. 信号量(Semaphore):允许多个线程访问共享资源,但限制同时访问的线程数量。
  3. 条件变量(Condition Variable):允许线程在某些条件下等待,并在条件满足时被唤醒。
  4. 读写锁(Read-Write Lock):允许多个线程同时读取共享资源,但在写入时会阻止其他线程的读取和写入。

通过这些机制,线程同步可以有效地避免数据竞争和不一致性,确保程序的正确执行。

相关文章:

第四天面试题

文章目录 1.什么叫 Java 的内存泄露与内存溢出&#xff1f;**1. 内存泄露&#xff08;Memory Leak&#xff09;****内存泄露的常见原因&#xff1a;****如何避免内存泄露&#xff1a;** **2. 内存溢出&#xff08;Out Of Memory, OOM&#xff09;****内存溢出的常见原因&#x…...

[论文阅读] SeeSR: Towards Semantics-Aware Real-World Image Super-Resolution

文章目录 一、前言二、主要贡献三、Introduction四、Methodology4.1 Motivation &#xff1a;4.2Framework Overview.** 一、前言 通信作者是香港理工大学 & OPPO研究所的张磊教授&#xff0c;也是图像超分ISR的一个大牛了。 论文如下 SeeSR: Towards Semantics-Aware Rea…...

面试题之箭头函数和普通函数有什么区别?

箭头函数&#xff08;Arrow Function&#xff09;和普通函数&#xff08;Regular Function&#xff09;是 JavaScript 中两种不同的函数定义方式&#xff0c;它们在语法、上下文&#xff08;this&#xff09;、原型链等方面存在显著区别。以下是它们的主要区别&#xff1a; 1. …...

jQuery AJAX 方法详解

jQuery AJAX 方法详解 引言 随着互联网技术的不断发展,前端开发领域的技术也在不断更新迭代。jQuery 作为一种广泛使用的前端JavaScript库,极大地简化了DOM操作和事件处理。在众多jQuery功能中,AJAX(Asynchronous JavaScript and XML)方法尤为突出,它允许我们在不重新加…...

深度集成DeepSeek大模型:WebSocket流式聊天实现

目录 5分钟快速接入DeepSeek大模型&#xff1a;WebSocket实时聊天指南创建应用开发后端代码 (Python/Node.js)结语 5分钟快速接入DeepSeek大模型&#xff1a;WebSocket实时聊天指南 创建应用 访问DeepSeek官网 前往 DeepSeek官网。如果还没有账号&#xff0c;需要先注册一个。…...

千峰React:组件使用(1)

事件 添加点击事件 function App() {const handClick () > {console.log(123)}return (<><button onClick{handClick}>点击</button></>) } export default App在react里也可以添加事件对象e 合成e 这个e和js里的e不太一样&#xff0c;是合成的…...

ram的使用——初始化很重要

背景 ram是非常常用的ip&#xff0c;前人的经验告诉我们&#xff0c;如果不对ram进行初始化直接读写&#xff0c;不定态在实际上板时会出现不可预知的问题。 我们需要对ram进行初始化写0操作&#xff0c;代码如下。需要注意&#xff0c;复位释放时立马写入可能存在复位抖动的…...

JVM深入理解

目录 JVM介绍&#xff1a; 解释&#xff1a; 特点&#xff1a; 整体构成&#xff1a; 执行过程&#xff1a; 运行时数据区&#xff1a; Java堆剖析&#xff1a; 堆内存区域划分 为什么要分代呢&#xff1f; 内存分配&#xff1a; 新生区与老年区配置比例&#xff1a…...

DeepSeek 开放平台无法充值 改用其他平台API调用DeepSeek-chat模型方法

近几天DeepSeek开放平台无法充值目前已经关闭状态&#xff0c;大家都是忙着接入DeepSeek模型 &#xff0c;很多人想使用DeepSeek怎么办&#xff1f; 当然还有改用其他平台API调用方法&#xff0c;本文以本站的提供chatgpt系统为例&#xff0c;如何修改DeepSeek-chat模型API接口…...

ImportError: cannot import name ‘FixtureDef‘ from ‘pytest‘

错误信息表明 pytest 在尝试导入 FixtureDef 时出现了问题。通常是由于 pytest 版本不兼容 或 插件版本冲突 引起的。以下是详细的排查步骤和解决方案&#xff1a; 1. 检查 pytest 版本 首先&#xff0c;确认当前安装的 pytest 版本。某些插件可能需要特定版本的 pytest 才能…...

懒人精灵本地离线卡密验证系统教程(不联网、安全稳定、省钱、永久免费、无任何限制)

1.合集懒人精灵本地离线卡密验证系统教程(不联网、安全稳定、省钱、永久免费、无任何限制)&#xff1a;https://www.bilibili.com/video/BV1M6rdYEEog/ 备注&#xff1a; 1.本地离线卡密采用最安全的非对称加解密技术&#xff0c;设备id采用最安全多重混合加密不可逆技术生成&…...

Rust编程语言入门教程 (六)变量与可变性

Rust 系列 &#x1f380;Rust编程语言入门教程&#xff08;一&#xff09;安装Rust&#x1f6aa; &#x1f380;Rust编程语言入门教程&#xff08;二&#xff09;hello_world&#x1f6aa; &#x1f380;Rust编程语言入门教程&#xff08;三&#xff09; Hello Cargo&#x1f…...

ArcGis和Super Map

1.ArcGIS ArcGIS 是美国环境系统研究所&#xff08;ESRI&#xff09;开发的一系列地理信息系统&#xff08;GIS&#xff09;软件产品的总称&#xff0c;它提供了一套全面的工具和服务&#xff0c;可用于采集、存储、分析、管理和展示地理数据&#xff0c;在众多领域都有广泛的…...

POI优化Excel录入

57000单词原始录入时间258S 核心代码: List<Word> wordBookList ExcelUtil.getReader(file.getInputStream()).readAll(Word.class);if (!CollectionUtil.isEmpty(wordBookList)) {for (Word word : wordBookList) {//逐条向数据库中插入单词wordMapper.insert(word);}…...

Zookeeper和Kafka的依赖关系

Zookeeper 和 Kafka 是紧密相关的,它们在功能上相互协作,共同为分布式系统提供支持,以下是它们的关系具体介绍: Kafka 依赖 Zookeeper 进行元数据管理 主题信息存储:Kafka 中的主题(Topic)相关信息,如主题的名称、分区数量、副本分布等都存储在 Zookeeper 中。当 Kafk…...

驱动开发、移植

一、任务明确&#xff1a;把创龙MX8的驱动 按照我们的要求 然后移植到 我们的板子 1.Linux系统启动卡制作&#xff0c; sd卡 先按照 《用户手册—3-2-Linux系统启动卡制作及系统固化》 把创龙的Linux系统刷进去。 2. 把TLIMX8-EVM的板子过一遍 把刚刚烧好系统的sd卡插入 创…...

RT-Thread+STM32L475VET6实现红外遥控实验

文章目录 前言一、板载资源介绍二、具体步骤1. 确定红外接收头引脚编号2. 下载infrared软件包3. 配置infrared软件包4. 打开STM32CubeMX进行相关配置4.1 使用外部高速时钟&#xff0c;并修改时钟树4.2 打开定时器16(定时器根据自己需求调整)4.3 打开串口4.4 生成工程 5. 打开HW…...

分布式大语言模型服务引擎vLLM论文解读

论文地址&#xff1a;Efficient Memory Management for Large Language Model Serving with PagedAttention 摘要 大语言模型&#xff08;LLMs&#xff09;的高吞吐量服务需要一次对足够多的请求进行批处理。然而&#xff0c;现有系统面临困境&#xff0c;因为每个请求的键值…...

Bio-ORACLE数据分享[decade 2010-2020] [Surface layers]

Bio-ORACLE数据分享[decade 2010-2020] [Surface layers] 文章目录 Bio-ORACLE数据分享[decade 2010-2020] [Surface layers]前言一、文件分享&#xff08;主要&#xff09;二、相关代码&#xff08;选看&#xff09;总结 Bio-ORACLE数据分享[decade 2010-2020] [Surface layer…...

MySQL六大日志的功能介绍。

前言 首先&#xff0c;MySQL的日志应该包括二进制日志&#xff08;Binary Log&#xff09;、错误日志&#xff08;Error Log&#xff09;、查询日志&#xff08;General Query Log&#xff09;、慢查询日志&#xff08;Slow Query Log&#xff09;、重做日志&#xff08;Redo …...

ChatGPT客户端无法在微软应用商店下载的解决方法

最近网页端的GPT4o只会用how can I assist you 回复了&#xff0c;查了一下发现是类似IP封锁/模型降级等等问题&#xff0c;总之解决方法就是下载客户端。客户端需要通过微软应用商店下载&#xff0c;但是下载时总会出现如下情况&#xff1a; 1.区域和语言没有设置为美国/英语导…...

数仓搭建(hive):DWS层(服务数据层)

DWS层示例: 搭建日主题宽表 需求 维度 步骤 在hive中建数据库dws >>建表 CREATE DATABASE if NOT EXISTS DWS; 建表sql CREATE TABLE yp_dws.dws_sale_daycount( --维度 city_id string COMMENT 城市id, city_name string COMMENT 城市name, trade_area_id string COMME…...

Ollama+DeepSeek+Open-WebUi

环境准备 Docker Ollama Open-WebUi Ollama 下载地址&#xff1a;Ollama docker安装ollama docker run -d \ -v /data/ollama/data:/root/.ollama \ -p 11434:11434 \ --name ollama ollama/ollama 下载模型 Ollama模型仓库 # 示例&#xff1a;安装deepseek-r1:7b doc…...

【笔记】LLM|Ubuntu22服务器极简本地部署DeepSeek+联网使用方式

2025/02/18说明&#xff1a;2月18日~2月20日是2024年度博客之星投票时间&#xff0c;走过路过可以帮忙点点投票吗&#xff1f;我想要前一百的实体证书&#xff0c;经过我严密的计算只要再拿到60票就稳了。一人可能会有多票&#xff0c;Thanks♪(&#xff65;ω&#xff65;)&am…...

FreeSwitch中mod_dptools和mod_easyroute两个模块及应用场景

FreeSWITCH 中的 mod_dptools 和 mod_easyroute 是两个功能不同的模块&#xff0c;分别服务于呼叫控制和动态路由场景。以下是详细介绍&#xff1a; mod_dptools 功能概述 mod_dptools&#xff08;Dialplan Tools&#xff09;是 FreeSWITCH 最核心的模块之一&#xff0c;提供了…...

【Java】泛型与集合篇 —— Set 接口

目录 Set 接口及实现类HashSet 类特点内部实现构造方法LinkedHashSet 类基本概念特点构造方法常用方法适用场景用 Set 对象实现集合运算TreeSet 类特性构造方法常用方法注意事项对象顺序自然排序定制排序注意事项Set 接口及实现类 HashSet 类 HashSet 是 Java 集合框架中 Set…...

DeepSeek 助力 Vue 开发:打造丝滑的右键菜单(RightClickMenu)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…...

数据结构与算法面试专题——堆排序

完全二叉树 完全二叉树中如果每棵子树的最大值都在顶部就是大根堆 完全二叉树中如果每棵子树的最小值都在顶部就是小根堆 设计目标&#xff1a;完全二叉树的设计目标是高效地利用存储空间&#xff0c;同时便于进行层次遍历和数组存储。它的结构使得每个节点的子节点都可以通过简…...

【Mysql】索引

【Mysql】索引 一、索引的简介二、索引结构2.1 Hash2.2 二叉搜索树2.3 B树2.4 B树 三、索引分类3.1 主键索引3.2 普通索引3.3 唯一索引3.4 全文索引3.5 聚集索引3.6 非聚集索引3.7 索引覆盖 四、使用索引4.1 自动创建索引4.2 手动创建索引4.2.1 主键索引4.2.2 唯一索引4.2.3 普…...

qt的下载安装详细介绍

下载 我们可以在国内的镜像网站上下载qt安装包&#xff0c;按需下载&#xff1a; 我的需求是在windows上运行&#xff0c;x64的qt5.15.2,所以我下载的是qt-unified-windows-x64-4.6.0-online.exe 下载完成之后&#xff0c;我们来到存放该exe文件的目录&#xff0c;打开命令窗…...

Eclipse插件开发六:使用Web前端技术开发AI助手页面

之前的过程中&#xff0c;我们都不怎么熟悉Eclipse的哪些API&#xff0c;样式也没发怎么去修改&#xff0c;现在我们要修改为用html的方式来编写. 准备一个AI助手聊天页面的html.css,js代码 效果如下所示。 1.快速demo 1.1.准备前端代码 确保准备的前端代码可以在浏览器正常…...

Jackson使用

Jackson 是一个功能强大的 JSON 处理库&#xff0c;除了基本的序列化和反序列化功能外&#xff0c;它还提供了许多其他功能&#xff0c;以满足不同的需求。以下是一些常用的高级功能&#xff1a; 0.普通序列化反序列化 序列化 import com.fasterxml.jackson.databind.ObjectM…...

Maven——Maven开发经验总结(1)

摘要 本文总结了 Maven 开发中的多个关键经验&#xff0c;包括如何根据版本号决定推送到 releases 或 snapshots 仓库&#xff0c;如何在构建过程中跳过测试&#xff0c;父项目如何控制子项目依赖版本&#xff0c;父项目依赖是否能传递到子项目&#xff0c;如何跳过 Maven dep…...

MyBatis-Plus之通用枚举

MyBatis-Plus之通用枚举 前言 MyBatis-Plus中提供了通用枚举&#xff0c;简单来说就是将数据库中的某一字段的代替的含义转换成真实的含义将数据展示给用户&#xff0c;用户在存储时也会将真实值转换成代替的数字存入到数据库中。举个例子&#xff1a;用户性别在数据库中存储…...

React通用登录/注销功能实现方案(基于shadcn/ui)

React通用登录/注销功能实现方案&#xff08;基于shadcn/ui&#xff09; 一、功能需求分析二、通用功能封装1. 通用登录表单组件2. 认证Hook封装 三、功能使用示例1. 登录页面实现2. 用户菜单实现 四、路由保护实现五、方案优势 一、功能需求分析 需要实现以下核心功能&#x…...

AI工具篇:利用DeepSeek+Kimi 辅助生成综述汇报PPT

随着科研和学术报告需求的增加&#xff0c;如何高效地准备一份结构清晰、内容充实的PPT已成为许多研究者的挑战。 传统的PPT制作过程繁琐&#xff0c;需要大量文献收集、数据分析和设计工作&#xff0c;而AI工具能够帮助提升效率&#xff0c;减少重复劳动。 本文将介绍如何使用…...

审计级别未启用扩展模式导致查询 DBA_AUDIT_TRAIL 时 SQL_TEXT 列为空

如果查询 DBA_AUDIT_TRAIL 时发现 SQL_TEXT 列为空&#xff0c;但其他字段&#xff08;如 OS_USERNAME、USERNAME、TIMESTAMP 等&#xff09;有数据&#xff0c;可能是由于以下原因之一。以下是可能的原因及解决方法&#xff1a; 1. 审计级别未启用扩展模式 默认情况下&#x…...

HTTP 和RESTful API 基础,答疑

一文搞懂RESTful API - bigsai - 博客园 1. API 路径 开头必须 /&#xff0c;表示绝对路径&#xff0c;不支持 . 或 ..&#xff08;相对路径&#xff09;。API 结尾 / 通常不需要&#xff0c;但部分框架会自动处理 / → 无 /。 ✅ 推荐 GET /api/v1/products # 资源集合…...

手写简易RPC(实践版)

首先了解rpc rpc-远程过程调用&#xff0c;openFeign&#xff0c;Dubbo都可以算作rpc&#xff0c;以微服务来具体说明&#xff0c;就是在本地不需要去发送请求&#xff0c;通过rpc框架&#xff0c;像调用本地方法一样调用其他服务的方法&#xff0c;本质上还是要经过网络&…...

Day6 25/2/19 WED

【一周刷爆LeetCode&#xff0c;算法大神左神&#xff08;左程云&#xff09;耗时100天打造算法与数据结构基础到高级全家桶教程&#xff0c;直击BTAJ等一线大厂必问算法面试题真题详解&#xff08;马士兵&#xff09;】https://www.bilibili.com/video/BV13g41157hK?p4&v…...

【DL】浅谈深度学习中的知识蒸馏 | 输出层知识蒸馏

目录 一 核心概念与背景 二 输出层知识蒸馏 1 教师模型训练 2 软标签生成&#xff08;Soft Targets&#xff09; 3 学生模型训练 三 扩展 1 有效性分析 2 关键影响因素 3 变体 一 核心概念与背景 知识蒸馏&#xff08;Knowledge Distillation, KD&#xff09;是一种模…...

机器学习PCA和LDA

主成分分析&#xff08;PCA, Principal Component Analysis&#xff09;和线性判别分析&#xff08;LDA, Linear Discriminant Analysis&#xff09;是两种常用的降维方法&#xff0c;它们虽然都用于数据降维&#xff0c;但核心思想和应用场景不同。 PCA&#xff08;主成分分析…...

tcp协议连接,和传输数据

1、连接 这个是通用的 2、传送数据 当连接建立后&#xff0c;客户端和服务器都可以主动发送数据&#xff0c;分别如下 1》客户端先发送数据 这里是单向的&#xff0c;服务器没有对客户端的数据内容进行应答&#xff0c;只是单纯的对报文应答ack 2》服务器先发送数据...

【异常错误】pycharm debug view变量的时候显示不全,中间会以...显示

异常问题&#xff1a; 这个是在新版的pycharm中出现的&#xff0c;出现的问题&#xff0c;点击view后不全部显示&#xff0c;而是以...折叠显示 在setting中这么设置一下就好了&#xff1a; 解决办法&#xff1a; https://youtrack.jetbrains.com/issue/PY-75568/Large-stri…...

Java基础——代理模式

代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问&#xff0c;这样就可以在不修改原目标对象的前提下&#xff0c;提供额外的功能操作&#xff0c;扩展目标对象的功能。 一、代理模式的主要作用 控制访问&#xff1a;通…...

解锁机器学习核心算法|主成分分析(PCA):降维的魔法棒

一、引言 在机器学习的庞大算法体系中&#xff0c;有十种算法被广泛认为是最具代表性和实用性的&#xff0c;它们犹如机器学习领域的 “十大神器”&#xff0c;各自发挥着独特的作用。这十大算法包括线性回归、逻辑回归、决策树、随机森林、K - 近邻算法、K - 平均算法、支持向…...

sql注入漏洞

目录 一、SQL注入概述 例子背景 正常情况下的查询 SQL注入攻击 利用优先级进行攻击 二、解决SQL注入 使用PreparedStatement接口 步骤和方法 1. 创建PreparedStatement对象 2. 向占位符传入值 3. 执行SQL语句 示例 总结 SQL 注入是一种常见的网络攻击手段。通俗来…...

spring微服务+dubbo框架,某一服务启动时提示多个bean存在

在java的springboot项目中使用DubboService的注解的实现类中&#xff0c;在引用本模块的类时&#xff0c;使用的DubboRefrence注解&#xff0c;在启动项目时报错&#xff0c;提示该类需要以一个bean对象&#xff0c;但是存在了两个&#xff0c;把DubboRefrence的注解改成Autowi…...

React useState 和 useEffect 使用坑点注意总结

React Hooks 使用注意事项 Area: Hooks Date: February 10, 2025 Important: &#x1f31f;&#x1f31f;&#x1f31f; React Hooks 注意事项 要点&#xff1a; useState 的初始化值 只在第一次渲染时计算&#xff0c;并且这个值不会随着组件重新渲染而更新。useEffect 可…...

使用rknn进行yolo11-pose部署

文章目录 概要生成ONNX生成RKNN实测效果概要 使用 RKNN 进行 YOLOv11 Pose 部署的必要性在于,RKNN 能将 YOLOv11 Pose 模型转化为适合 Rockchip 硬件平台(如 RV1109、RV1126)执行的格式,充分利用其 AI 加速功能,显著提高推理速度和效率。此外,RKNN 提供模型优化(如量化…...