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

图灵300题-21~40-笔记002

图灵300题

图灵面试题视频:https://www.bilibili.com/video/BV17z421B7rB?spm_id_from=333.788.videopod.episodes&vd_source=be7914db0accdc2315623a7ad0709b85&p=20。
本文是学习笔记,如果需要面试没有时间阅读原博文,可以快速浏览笔记。
推荐深度阅读对应书籍或者知识点原文,避免碎片化学习。

21.Java中的异常体系

Java 的所有异常都来自顶层父类 Throwable
Throwable 包含两个重要子类:ErrorException

  • Error
    表示程序运行过程中发生的严重错误,一旦出现此类错误,程序会被迫停止运行。
  • Exception
    表示程序运行时发生的异常,进一步分为两部分:
    • RuntimeException(运行时异常)
      通常由编程错误导致,例如空指针异常、数组越界异常等。
    • 受检查的异常(Checked Exception)
      多发生在编译期间,需要程序员通过显式使用 try-catch 块处理,或声明抛出的异常。

22. Java类加载器

JDK自带有三个类加载器:bootstrap ClassLoaderExtClassLoaderAppClassLoader

  • BootStrapClassLoaderExtClassLoader的父类加载器,默认负责加载%JAVA_HOME%lib下的jar包和class文件。
  • ExtClassLoaderAppClassLoader的父类加载器,负责加载%JAVA_HOME%/lib/ext文件夹下的jar包和class类。
  • AppClassLoader是自定义类加载器的父类,负责加载classpath下的类文件。还可继承ClassLoader实现自定义类加载器。

23.类加载器双亲委派模型

  • Java 中存在的三层类加载器
    BootstrapClassLoader
    ExtensionClassLoader
    AppClassLoader

  • 双亲委派模型的工作机制
    当一个类加载器(如 AppClassLoader)收到加载类的请求时,它首先不会尝试自己去加载这个类。在这个过程中,会先使用 findLoadedClass 方法来检查该类是否已经被加载过。如果没有被加载,类加载器不会自行去加载,而是把请求委派给父类加载器(ExtensionClassLoader),按照层级依次向上委派,父类加载器又会将请求委派给它自己的父类加载器(BootstrapClassLoader) 。只有当父类加载器无法完成加载任务(即父类加载器返回 null)时,子类加载器才会尝试自己去加载这个类。 这样可以避免重复加载,同时也保证了 Java 核心类库的安全性。

24. JVM判断对象可回收的方式

JVM判断对象是否可被回收主要有两种方式:

  • 引用计数法:每个对象都有一个引用计数属性。当新增一个引用时,计数加1;引用释放时,计数减1。当引用计数为0时,该对象可被回收。然而,这种方法存在循环引用的问题,比如对象A引用对象B,对象B又引用对象A,即使它们都不再被其他部分的程序使用,由于相互引用,引用计数始终不为0,导致无法被回收。
  • 可达性分析法:从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,证明此对象不可用,会被虚拟机判断为可回收对象。GC Roots包括以下几种对象:
    • 虚拟机栈(栈帧中的本地变量表)中引用的对象;
    • 方法区中类静态属性引用的对象;
    • 方法区中常量引用的对象;
    • 本地方法栈中JNI(即一般说的Native方法)引用的对象。

需要注意的是,可达性算法中的不可达对象并非立即死亡,对象有一次自我拯救的机会。对象被系统宣告死亡至少要经历两次标记过程:第一次是经过可达性分析发现没有与GC Roots相连接的引用链;第二次是在由虚拟机自动建立的过程中。

25. JVM中的线程共享区

JVM运行时数据区中,堆区和方法区是所有线程共享的,而栈、本地方法栈、程序计数器是每个线程独有的。具体结构如下:

在这个结构中,堆区用于存放对象实例,方法区存储类的元数据、常量等信息,它们作为线程共享区,承担着重要的数据存储任务;而线程独有的区域则各自负责不同的线程执行相关功能。

26. JVM的垃圾回收算法

JVM常见的垃圾回收算法有以下几种:

  • Mark - Sweep标记清除算法:该算法分为标记和清除两个阶段。在标记阶段,会把垃圾内存标记出来;清除阶段则直接将标记的垃圾内存回收。这种算法虽然简单,但会产生大量的内存碎片,影响后续内存分配效率。
  • Copying拷贝算法:将内存按容量划分为大小相等的两块区域(一般称为 From Space 和 To Space) ,每次只使用其中一块。当这块内存使用完,进行垃圾回收时,会将还存活的对象一次性拷贝到另一块未使用的内存空间中,然后把原来使用的内存空间一次性清理掉。由于是将存活对象整体拷贝到新的区域,然后直接清理旧区域,所以清理过程非常高效,没有标记和清除的复杂操作,也不会产生内存碎片,使得内存分配更加连续和高效。需要将内存划分为两块,每次只能使用其中一半,这就导致内存的实际利用率只有 50% ,空间浪费较为严重。
  • Mark - Compack标记压缩算法:此算法的标记阶段和标记清除算法相同,但在完成标记之后,不是直接清理垃圾内存,将存活对象往内存一端移动,然后清除移动后存活对象所在区域边界之外的所有内存,有效解决了标记清除算法产生内存碎片的问题。

27. JVM的垃圾回收器及相关概念

这部分内容主要涉及JVM垃圾回收器的类型、工作原理,以及STW、三色标记等相关概念。

  • STW(Stop - The - World):是垃圾回收算法执行过程中,将JVM内存冻结的一种状态。在STW状态下,除了GC线程外,Java的所有线程都停止执行,native方法虽然可以执行,但不能与JVM交互。减少STW时间是GC算法优化以及JVM调优的重点。
  • 垃圾回收器分类及工作方式
    • Serial串行回收器:整体过程简单,进行GC时直接暂停,GC完成后继续。它是早期的垃圾回收器,仅由一个线程执行GC操作。在多CPU架构下,性能会严重下降,适用于几十兆的小内存空间。
    • Parallel并行回收器:在串行回收器的基础上增加了多线程GC功能。PS + PO组合是JDK1.8默认的垃圾回收器,在多CPU架构下性能比Serial回收器高很多。
    • CMS(Concurrent Mark Sweep)回收器:核心思想是将STW时间打散,使部分GC线程与用户线程并发执行。整个GC过程分为四个阶段:
      • 初始标记阶段:STW,仅标记出根对象直接引用的对象;
      • 并发标记:与应用程序并发执行,继续标记其他对象;
      • 重新标记:STW,对并发执行阶段的对象进行重新标记;
      • 并发清除:并行清除垃圾。但在清除过程中,应用程序会不断产生新的垃圾,即浮动垃圾,这些垃圾需留到下一次GC过程处理。
    • G1回收器:其内存模型实际不分代,但逻辑上进行分代。堆内存不再划分老年代和新生代,而是被划分为一个个小内存块,称为Region,每个Region可隶属于不同年代。逻辑分代是通过不同 Region 承担类似传统分代中新生代和老年代的功能。GC分为五个阶段:
      • 初始标记:标记出GCRoot直接引用的对象,STW
      • 标记Region:通过RSet标记出上一阶段标记的Region引用到的Old区Region
      • 并发标记阶段:与CMS的步骤类似,但遍历范围仅为第二步标记出的Region
      • 重新标记:与CMS中的重新标记过程相似;
      • 垃圾清理:与CMS不同,G1可采用拷贝算法,直接将整个Region中的对象拷贝到另一个Region,且此阶段只选择垃圾较多的Region进行清理。

28.三色标记算法

三色标记算法是一种在并发垃圾回收中常用的算法,它将对象标记为三种颜色:白色、灰色和黑色,以此来追踪对象的引用关系,判断对象是否存活。

  • 白色对象:表示尚未被垃圾回收器访问过的对象,在垃圾回收开始阶段,所有对象默认都是白色。
  • 灰色对象:表示自身被访问过,但它引用的对象还未全部被访问的对象。也就是说,灰色对象是那些已经被发现,但它所关联的对象还在待检查状态。
  • 黑色对象:表示自身以及它引用的所有对象都已经被访问过的对象。在垃圾回收过程结束时,黑色对象被认为是存活的对象,白色对象则被判定为垃圾对象(在没有漏标和错标情况下)。
执行过程
  • 初始标记阶段:从GC Roots开始扫描,将直接关联的对象标记为灰色,这一阶段会产生STW(Stop-The-World),暂停用户线程,以确保标记的准确性。
  • 并发标记阶段:垃圾回收器开始并发地遍历灰色对象,将其引用的对象标记为灰色,同时把自身标记为黑色,放入黑色集合中。在这个过程中,用户线程可以继续运行,新创建的对象会被标记为白色。由于用户线程和垃圾回收线程并发执行,可能会出现对象引用关系的变化,这就可能导致错标记和漏标记问题。
  • 最终标记阶段:再次短暂STW,处理并发标记阶段因用户线程执行导致的引用关系变化,确保所有存活对象都被正确标记为黑色,所有垃圾对象都为白色。
错标记和漏标记问题及解决方法
  • 错标记问题:在并发标记阶段,由于用户线程和垃圾回收线程并发执行,可能会出现将垃圾对象错误标记为存活对象(即错标记为黑色)的情况。例如,一个白色对象原本是垃圾对象,但在垃圾回收器扫描到它之前,被一个灰色对象引用了,之后垃圾回收器将这个灰色对象及其引用的白色对象都标记为黑色,导致垃圾对象未被回收。
  • 漏标记问题:是指将存活对象错误标记为垃圾对象(即漏标记为白色)的情况。比如,在并发标记过程中,一个黑色对象原本引用了一个白色对象(该白色对象是存活的),但在垃圾回收器扫描完这个黑色对象之后,用户线程将这个引用断开了,同时另一个灰色对象引用了这个白色对象,但由于垃圾回收器已经扫描过这个灰色对象,没有重新扫描它引用的对象,就导致这个白色存活对象被误判为垃圾对象。
  • 解决方法:为了解决错标记和漏标记问题,通常采用“增量更新”和“原始快照”(SATB,Snapshot At The Beginning)这两种策略。
    • 增量更新:当一个黑色对象引用了一个白色对象时,将这个引用关系记录下来(可以通过写屏障实现),在最终标记阶段重新扫描这些记录的引用关系,确保白色对象被正确标记。
    • 原始快照:在垃圾回收开始时,对对象的引用关系进行一次快照记录。在并发标记过程中,当发现对象的引用关系发生变化时,对比快照中的引用关系,如果发现有对象的引用被删除,就将这个对象标记为灰色,确保其不会被误判为垃圾对象。
优势与意义
  • 提高并发性能:三色标记算法允许垃圾回收器在一定程度上与用户线程并发执行,减少了垃圾回收过程中STW的时间,提高了系统的整体性能和响应速度。
  • 适用于现代JVM:在现代JVM的垃圾回收器中,如CMS(Concurrent Mark Sweep)和G1(Garbage-First)等,三色标记算法都发挥着重要作用,帮助这些垃圾回收器实现高效的并发垃圾回收,更好地管理内存资源。

29. 确定对象是否为垃圾及GC Root的概念

确定一个对象是否为垃圾有以下两种方式:

  • 引用计数:给堆内存中的每个对象记录一个引用个数,当引用个数为0时,认为该对象是垃圾。这是早期JDK使用的方式,但无法解决循环引用问题。
  • 根可达算法:从内存中的引用根对象向下查找引用,找不到引用的对象即为垃圾。GC Root包括虚拟机栈(栈帧中的本地变量表)中引用的对象以及本地方法栈中引用的对象、class类、运行时常量池(run - time constant pool)、静态变量(static reference) 。

30. 项目中排查JVM问题的方法

排查JVM问题,根据系统状态不同,有不同的排查方法:

  • 对于正常运行的系统
    • 可以使用jmap查看JVM中各个区域的使用情况;
    • 通过jstack查看线程的运行情况,比如是否有线程阻塞、是否出现死锁等;
    • 利用jstat命令查看垃圾回收情况,尤其是fullgc,若发现fullgc频繁,就需要进行调优;
    • 通过上述命令的结果,或者借助jvisualvm等工具进行分析;
    • 初步猜测频繁发生fullgc的原因,如果频繁发生fullgc但未出现内存问题,说明fullgc回收了很多对象,这些对象最好在younggc阶段就被回收,避免进入老年代。此时可考虑是否因为存活时间不长的对象较大,导致年轻代放不下而直接进入老年代,尝试加大年轻代大小,若修改后fullgc减少,则证明修改有效;
    • 找到占用CPU最多的线程,定位到具体方法,优化该方法的执行,看是否能避免某些对象的创建,从而节省内存。
  • 对于发生OOM的系统
    • 一般在生产系统中会设置当系统发生OOM时,生成当时的dump文件(-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/base);
    • 使用jsisualvm等工具分析dump文件;
    • 根据dump文件找到异常的实例对象和占用CPU高的异常线程,定位到具体代码;
    • 然后进行详细的分析和调试。

JVM调优是一个反复的过程,需要不断分析、推理、实践、总结,才能最终定位并解决问题。

31. 线程的生命周期与状态

线程通常具有五种状态:

  • 新建状态(New):新创建了一个线程对象,此时线程尚未启动。
  • 就绪状态(Runnable):线程对象创建后,其他线程调用了其start方法,该线程进入可运行线程池,等待获取CPU使用权。
  • 运行状态(Running):就绪状态的线程获取到CPU资源,开始执行程序代码。
  • 阻塞状态(Blocked):线程因某种原因放弃CPU使用权,暂时停止运行。阻塞状态又分为以下三种情况:
    • 等待阻塞:运行的线程执行wait方法,会释放占用的所有资源,JVM将其放入“等待池”。该状态下线程不能自动唤醒,必须依靠其他线程调用notifynotifyAll方法才能被唤醒,waitObject类的方法;
    • 同步阻塞:运行的线程在获取对象的同步锁时,若同步锁被其他线程占用,VM会把该线程放入“锁池”;
    • 其他阻塞:运行的线程执行sleepjoin方法,或者发出I/O请求时,JVM会将其置为阻塞状态。当sleep状态超时、join等待的线程终止或超时、或者I/O处理完毕时,线程重新转入就绪状态,sleepThread类的方法。
  • 死亡状态:线程执行完所有任务或出现异常等情况后,生命周期结束。

PS:spring源码注解只有阻塞状态,没有细分。

32. sleep()、wait()、join()、yield()的区别

这几个方法在功能和使用场景上存在明显区别:

  • 锁池和等待池:所有竞争同步锁的线程会被放入锁池。当对象的锁被某个线程获取后,其他线程需在锁池等待。当前面的线程释放同步锁后,锁池中的线程竞争同步锁,获取锁的线程进入就绪队列等待CPU资源分配。调用wait()方法后,线程会进入等待池,等待池中的线程不会竞争同步锁。只有调用notify()notifyAll()后,等待池中的线程才会开始竞争锁,notify()随机从等待池选择一个线程放入锁池,notifyAll()则将等待池中的所有线程放入锁池。
  • 方法区别
    • sleepThread类的静态本地方法,waitObject类的本地方法;
    • sleep方法不会释放lock,而wait会释放并加入等待队列。sleep会释放CPU执行资格和执行权,暂停线程运行,定时时间结束后重新获取CPU资源参与调度。若sleep时线程持有锁,该锁不会被释放,其他需要该锁的线程无法获取。如果在睡眠期间其他线程调用该线程的interrupt方法,线程会抛出InterruptedException异常返回,这点和wait相同;
    • sleep方法不依赖于同步器synchronized,而wait需要依赖synchronized关键字;
    • sleep不需要被唤醒(休眠结束后自动退出阻塞),wait则需要(不指定时间时需被其他线程中断);
    • sleep一般用于当前线程休眠或轮循暂停操作,wait多用于多线程之间的通信;
    • sleep会让出CPU执行时间并强制上下文切换,wait则不一定,wait后可能有机会重新竞争到锁继续执行。
    • yield()执行后线程直接进入就绪状态,释放CPU执行权,但保留CPU执行资格,因此下次CPU调度时该线程仍有可能获取执行权继续执行。
    • join()执行后线程进入阻塞状态,例如在线程B中调用线程A的join(),线程B会进入阻塞队列,直到线程A结束或被中断。

33. 对线程安全的理解

线程安全本质上与内存安全相关。堆是共享内存,可被所有线程访问。当多个线程访问一个对象时,若无需额外的同步控制或协调操作,调用该对象的行为能获得正确结果,则称这个对象是线程安全的。

堆是进程和线程共有的空间,分为全局堆和局部堆。全局堆是未分配的空间,局部堆是用户分配的空间。堆在操作系统初始化进程时分配,运行过程中可向系统申请额外堆空间,使用完毕后需归还,否则会导致内存泄漏。

在Java中,堆是Java虚拟机管理的内存中最大的一块,是所有线程共享的内存区域,在虚拟机启动时创建,主要用于存放对象实例和数组。

栈是每个线程独有的,用于保存线程运行状态和局部自动变量。栈在线程启动时初始化,每个线程的栈相互独立,因此栈是线程安全的。操作系统在切换线程时会自动切换栈。栈空间无需在高级语言中显式分配和释放。

主流操作系统大多是多任务的,每个进程只能访问分配给自己的内存空间,这由操作系统保障。进程内的所有线程都可访问堆内存,这是可能出现线程安全问题的潜在原因。

34. 守护线程的理解

守护线程是为所有非守护线程提供服务的线程,它依赖整个进程运行,自身生死对进程影响不大。当所有非守护线程结束,程序结束时,守护线程会被直接中断。
使用守护线程时需要注意以下几点:

  • 由于守护线程的终止不可控,不要将IO、文件操作等重要逻辑分配给它;
  • GC垃圾回收线程是经典的守护线程。当程序中没有运行的线程,不再产生垃圾时,垃圾回收器无事可做,此时若垃圾回收线程是JVM上仅剩的线程,它会自动离开。它在低级状态运行,实时监控和管理系统中的可回收资源;
  • 应用场景方面,适合为其他线程提供服务支持,或者在程序结束时无需关注其是否正常结束的场景。对于关键事务,如数据库录入或更新等不能中断的操作,不应使用守护线程;
  • 使用thread.setDaemon(true)设置线程为守护线程时,必须在thread.start()之前,否则会抛出IllegalThreadStateException异常。正在运行的常规线程不能被设置为守护线程;
  • 在Daemon线程中产生的新线程也是Daemon线程;
  • 守护线程不能用于访问固有资源,如读写操作或计算逻辑,因为它可能在任何时候甚至操作中途被中断;
  • Java自带的多线程框架,如ExecutorService,会将守护线程转换为用户线程,所以在该框架中使用后台线程时不能直接使用守护线程。

35. ThreadLocal的底层原理

ThreadLocal是Java提供的线程本地存储机制,可将数据缓存在某个线程内部,该线程能在任意时刻、任意方法中获取缓存数据。
其底层通过ThreadLocalMap实现,每个Thread对象(注意不是Threadlocal对象)都有一个ThreadlocalMapThreadlocalMapkeyThreadLocal对象,value为需要缓存的值。

在线程池中使用ThreadLocal可能会导致内存泄漏。因为ThreadLocal对象使用完后,其设置的keyvalue(即Entry对象)应被回收,但线程池中的线程不会回收,线程对象通过强引用指向ThreadlocalMapThreadLocalMap又通过强引用指向Entry对象,从而导致Entry对象无法被回收。解决办法是在使用完Threadlocal对象后,手动调用其remove方法,清除Entry对象。

ThreadLocal的经典应用场景是连接管理,即一个线程持有一个连接,该连接对象可在不同方法间传递,且线程之间不共享同一个连接。

36. 并发、并行、串行的区别

  • 串行:在时间上不存在重叠,前一个任务完成后,下一个任务才会开始。例如单线程依次处理多个文件的读写操作,必须按顺序逐个进行。
  • 并行:多个任务在同一时刻同时执行,互不干扰。就像多核CPU可以同时处理不同的任务,提高整体处理效率。
  • 并发:允许多个任务相互干扰。在同一时间点,只有一个任务在运行,但多个任务可交替执行。例如在单线程环境下,多个任务通过时间片轮转的方式交替执行,从宏观上看好像是同时进行。

37. 并发的三大特性

并发的三大特性涉及关键字volatilesynchronizedfinal ,具体内容如下:

  • 有序性:虚拟机在编译代码时,对于改变顺序后不影响最终结果的代码,可能会进行重排序。虽然重排序对变量值可能无影响,但在多线程环境下可能导致线程安全问题。例如,对共享变量的操作顺序若被重排序,可能使数据不一致。
  • 原子性:原子性指一个操作在CPU执行过程中不会被中断,要么全部执行完成,要么都不执行。以转账操作为例,从账户A向账户B转1000元,包含从账户A减去1000元,往账户B加上1000元这两个操作,这两个操作必须全部完成,否则会出现数据错误。关键字synchronized可保证操作的原子性。
  • 可见性:当多个线程访问同一个变量时,一个线程修改变量值后,其他线程能立即看到修改后的结果。若两个线程在不同CPU上,线程1修改变量i的值后未刷新到主存,线程2使用i时,获取的仍是之前的值,这就是可见性问题。volatile关键字可保证变量的可见性,确保一个线程对变量的修改能及时被其他线程看到。

38. Java死锁的避免方法

  • 造成死锁的原因
    • 资源独占性:一个资源每次只能被一个线程使用。
    • 不可剥夺条件:一个线程在阻塞等待某个资源时,不会释放已占有的资源 。
    • 占有并等待:一个线程已经获得了一些资源,在未使用完之前,不能被强行剥夺。
    • 循环等待:若干线程形成头尾相接的循环等待资源关系。只有这四个条件同时满足,才会产生死锁。
  • 避免死锁的策略:在开发过程中,要避免死锁,只需破坏其中一个条件即可。由于前三个条件是锁的基本特性,难以改变,所以通常通过破坏循环等待条件来避免死锁。具体措施如下:
    • 控制加锁顺序:保证每个线程按照相同的顺序获取锁。比如,如果线程A获取锁的顺序是lock1lock2,那么其他线程也应遵循同样的顺序,这样可以有效避免循环等待锁的情况发生。
    • 设置加锁时限:为锁设置一个超时时间。当线程等待锁的时间超过该时限时,线程放弃等待并释放已持有的资源,从而打破死锁的条件。
    • 实施死锁检测:采用特定的工具或算法,定期检查系统中是否存在死锁。一旦发现死锁,及时采取措施进行解决,这是一种有效的预防机制。

39. 使用线程池的原因及线程池参数解析

  • 使用线程池的原因
    • 降低资源消耗:通过复用已创建的线程,减少线程创建和销毁带来的资源开销,提高线程的利用率。
    • 提高响应速度:当任务到达时,线程池中已有可用线程,无需等待线程创建即可立即执行任务,从而加快系统的响应速度。
    • 便于线程管理:线程是宝贵的资源,使用线程池可以对线程进行统一的分配、调优和监控,增强线程的可管理性。
  • 线程池参数解析
    • corePoolSize:表示核心线程数,即正常情况下创建的工作线程数量。这些线程创建后会一直存在,不会被轻易销毁,属于常驻线程。例如,在一个Web服务器线程池中,可根据日常平均请求量设置合适的核心线程数。
    • maximumPoolSize:代表最大线程数,与核心线程数相对应。当任务量增加,核心线程数被用完且任务队列已满时,线程池会创建新的线程,但线程总数不会超过最大线程数。
    • keepAliveTimeunit:用于设置超出核心线程数之外的线程的空闲存活时间。核心线程不会被销毁,而超出核心线程数的部分线程如果在指定的空闲时间内没有任务执行,就会被销毁。可以通过setKeepAliveTime方法来设置这个空闲时间。
    • workQueue:用于存放等待执行的任务。当核心线程都在忙碌时,新的任务会被放入队列中。当队列已满且任务仍持续进入时,线程池会开始创建新的线程来处理任务。
    • ThreadFactory:是一个线程工厂,负责创建执行任务的线程。可以使用默认的线程工厂,其创建的线程都在同一个组内,具有相同的优先级,且都不是守护线程。也可以根据业务需求自定义线程工厂。
    • Handler:即任务拒绝策略。当出现以下两种情况时会触发任务拒绝:一是调用shutdown等方法关闭线程池后,若此时还有任务提交,线程池会拒绝;二是当线程池达到最大线程数,且任务队列已满,无法再处理新提交的任务时,也会拒绝该任务 。

相关文章:

图灵300题-21~40-笔记002

图灵300题 图灵面试题视频:https://www.bilibili.com/video/BV17z421B7rB?spm_id_from333.788.videopod.episodes&vd_sourcebe7914db0accdc2315623a7ad0709b85&p20。 本文是学习笔记,如果需要面试没有时间阅读原博文,可以快速浏览笔…...

蓝桥杯--bfs专题第二个题目(leetcode103二叉树)

文章目录 1.题目概述2.思路分析3.代码分析 1.题目概述 这个题目是关于二叉树的锯齿形的遍历:这个锯齿形是什么意思呢?简单的通俗的解释,就是S型的,例如下面的这个示例里面的二叉树: 第一行从左到右:但是只…...

React 知识回顾(HOC、合成事件、Fiber)

HOC 嗯,用户问的是HOC是什么以及它能用来做什么。我需要先理解HOC的基本概念,然后整理它的用途。根据搜索结果,HOC是React中的高阶组件,用来复用逻辑。网页1提到HOC是一个函数,接收组件返回新组件,属于设计…...

s1: Simple test-time scaling 【论文阅读笔记】

s1: Simple test-time scaling 关于test-time scaling 这个概念其实是相对 train scaling而言的。train scalling 指的是增加训练数据,增加训练flops等等,投入更多资源在train上。test-time scaling,其实现在简化点的理解,就是 …...

基于 Milvus 和 BiomedBERT 的医学文献智能搜索系统

前言 随着医学研究的不断深入,文献数量呈爆炸式增长,如何快速从海量文献中提取关键信息成为一大挑战。最近,我基于 Milvus 向量数据库和 BiomedBERT 嵌入模型,开发了一个智能搜索系统,支持语义搜索和关键词匹配&#…...

ASP.NET Web的 Razor Pages应用,配置热重载,解决.NET Core MVC 页面在更改后不刷新

Razor Pages应用,修改页面查看修改效果,如果没有热重载,改一句话跑一次,这个活就没法干了。 1、VS2022中的NuGet中安装RuntimeCompilation Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation 需要配套你的.net sdk版本&#x…...

MySQL 对text类型字段添加索引

对于 MySQL 中的 text 类型字段,可以通过以下步骤向其添加索引: 创建辅助字段:创建一个辅助字段,将该字段的一部分数据转移到辅助字段中。例如,可以创建一个 varchar 类型的字段来存储 text 字段的前缀。 添加索引&am…...

深入解析SQL2API平台:数据交互革新者

在数字化转型持续深入的当下,企业对数据的高效利用与管理的需求愈发迫切。SQL2API平台应运而生,成为助力企业突破数据交互困境的有力工具,特别是它由麦聪软件基于DaaS(数据即服务)产品创新衍生而来,备受业界…...

@Autowired 和 @Resource 注解的区别

前言 Autowired 和 Resource 是 Spring 中用于依赖注入的注解,但两者在实现机制和使用方式上有显著差异。 主要区别 1.来源不同 Autowired:由 Spring 框架提供(org.springframework.beans.factory.annotation),与 S…...

稳定运行的以ElasticSearch数据库为数据源和目标的ETL性能变差时提高性能方法和步骤

在使用 Elasticsearch 作为数据源和目标的 ETL(Extract, Transform, Load)过程中,性能逐渐变差的原因可能有很多,比如查询效率下降、集群负载过高、资源配置不合理等。 性能的提升通常需要从多个方面入手,尤其是在处理…...

游戏引擎学习第182天

回顾和今天的计划 昨天的进展令人惊喜,原本的调试系统已经被一个新的系统完全替换,新系统不仅能完成原有的所有功能,还能捕获完整的调试信息,包括时间戳等关键数据。这次的替换非常顺利,效果很好。 今天的重点是在此基…...

EJS缓存解决多页面相同闪动问题

基于 EJS 的模板引擎特性及其缓存机制,以下是关于缓存相同模块的详细解答: 一、EJS 缓存机制的核心能力 模板编译缓存 EJS 默认会将编译后的模板函数缓存在内存中,当相同模板文件被多次渲染时,会直接复用已编译的模板函数&#x…...

【MySQL】mysql日志文件

目录 日志文件特征 错误日志(Error log ) 常规查询日志(General query log ) 慢速查询日志(Slow query log ) 审计日志(Audit log ) 二进制日志(Binary log &#…...

【C++】STL性能优化实战

STL性能优化实战 STL (Standard Template Library) 是 C 标准库的核心部分,提供了各种容器、算法和迭代器。虽然 STL 提供了强大的功能,但不恰当的使用可能导致性能问题。下面我将详细介绍 STL 性能优化的实战技巧,并通过具体案例说明。 1.…...

Playwright + MCP:用AI对话重新定义浏览器自动化,效率提升300%!

一、引言:自动化测试的“瓶颈”与MCP的革新 传统自动化测试依赖开发者手动编写脚本,不仅耗时且容易因页面动态变化失效。例如,一个简单的登录流程可能需要开发者手动定位元素、处理等待逻辑,甚至反复调试超时问题。而MCP&#xf…...

12-scala样例类(Case Classes)

例类(Case classes)和普通类差不多,只有几点关键差别,接下来的介绍将会涵盖这些差别。样例类非常适合用于不可变的数据。 定义一个样例类 一个最简单的样例类定义由关键字case class,类名,参数列表&#…...

WPF 与 C# 开发深度剖析

一、引言 在当今的软件开发领域,Windows 平台依旧占据着重要的地位。而 WPF(Windows Presentation Foundation)作为微软推出的一款强大的用户界面(UI)框架,为开发者提供了丰富的功能和灵活的设计方式&…...

【工具使用-编译器】VScode(Ubuntu)使用

1. VScode的快捷键 快捷键功能说明Ctrl+Shift+P / F1显示命令面板Ctrl+P快速打开文件Ctrl+Shift+N新建窗口Ctrl+Shift+W关闭窗口Ctrl+,打开设置Ctrl+K Ctrl+S打开快捷键设置Ctrl+X剪切行(无选中时剪切整行)Ctrl+C复制行(无选中时复制整行)Alt+↑ / Alt+↓向上/向下移动行Sh…...

C# SerialPort 使用详解

总目录 前言 在工业控制、物联网、嵌入式开发等领域,串口通信(Serial Port Communication)是连接串行设备(如条码扫描器、GPS接收器等)与计算机的重要手段。C# 提供了内置的 SerialPort 类,简化了串口开发…...

数据结构--二叉排序树

一、二叉排序树的定义 二叉排序树&#xff0c;又称二叉查找树。 性质&#xff1a; 左子树结点值<根结点值<右子树结点值&#xff08;进行中序遍历&#xff0c;可以得到一个递增的有序序列&#xff09; 二、查找操作 利用二叉排序树的性质&#xff0c;如果树空&#xff0c…...

FPGA的直方图均衡

文章目录 一、直方图均衡二、代码实现三、仿真 一、直方图均衡 直方图均衡&#xff08;Histogram Equalization&#xff09;是一种用于增强图像对比度的图像处理技术。它通过重新分配图像像素的灰度值&#xff0c;使得图像的灰度直方图在整个灰度范围内均匀分布&#xff0c;从而…...

使用Python将视频转化为gif

使用Python将视频转化为gif 一、前言二、准备三、测试 一、前言 最近想把喜欢的视频片段作成gif&#xff0c;就试着用Python做了下&#xff0c;感觉效果还行&#xff0c;这里做个记录。 二、准备 先下载安装对应的库&#xff0c;命令如下&#xff1a; pip install moviepy …...

基于javaweb的SpringBoot雪具商城系统设计与实现系统(源码+文档+部署讲解)

​ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、…...

Harbor镜像仓库迁移与高可用集群搭建HTTPS实现实战指南

实验环境 Ubuntu22.04操作系统 registry节点 10.0.0.91 master节点 10.0.0.92 backup节点 10.0.0.93 在企业信息化建设的不同演进阶段&#xff0c;私有镜像仓库的选型策略存在显著差异。近期主导完成某企业级容器镜像仓库升级项目&#xff0c;成功实现Docker Registry至Ha…...

redis--JavaSpring客户端

目录 一、引言 二、配置 三、相关操作 四、总结 一、引言 本篇文章会将redis与spring项目进行结合&#xff0c;看看再spring项目中&#xff0c;redis是如何使用的 二、配置 三、相关操作 四、总结 在spring项目中的使用和在基础项目上的使用有差异&#xff0c;但是差异并不大…...

JavaWeb3

聚合函数&#xff1a;把某一列的数据计算。count,max,min,avg,sum select count(id) from wife;-- 统计个数&#xff0c;不计算null&#xff0c;统计常量表示个数 select count(*) from wife; select min(id) from wife; select avg(age) from wife; 分组查询 select name,c…...

SAP-ABAP:SAP数据集成全场景技术指南(BAPI、RFC、IDOC、BATCHJOB、ODATA、WEBSERVICE):从实时交互到批量处理

SAP数据集成全场景技术指南:从实时交互到批量处理 #mermaid-svg-hpPMerJYUerla0BJ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-hpPMerJYUerla0BJ .error-icon{fill:#552222;}#mermaid-svg-hpPMerJYUerla0BJ .er…...

QT笔记----QCheckBox

文章目录 概要1、QCheckBox 的基本概念2、单个QCheckBox3、多个QCheckBox同时应用3.1、实现效果3.2、实现Demo 概要 在 Qt 应用程序开发中&#xff0c;QCheckBox 是一个常用的用户界面元素&#xff0c;它允许用户在两种状态&#xff08;选中和未选中&#xff09;之间进行切换&a…...

试试智能体工作流,自动化搞定运维故障排查

APO 1.5.0版本全新推出的智能体工作流功能&#xff0c;让运维经验不再零散&#xff01;只需将日常的运维操作和故障排查经验转化为标准化流程&#xff0c;就能一键复用&#xff0c;效率翻倍&#xff0c;从此告别重复劳动&#xff0c;把时间留给更有价值的创新工作。更贴心的是&…...

3.24[Q]Linux

我正在学习Linux&#xff0c;Linux设备管理是怎样的&#xff1f;详细解释&#xff0c;越细节越好 我正在学习Linux&#xff0c;在Linux设备管理中&#xff0c;什么是char device&#xff1f;以及block,usb device?详细解释&#xff0c;越细节越好 我正在学习Linux&#xff0…...

深度学习——图像相似度评价指标

这里写目录标题 PSNR&#xff08;Peak Signal-to-Noise Ratio&#xff0c;峰值信噪比&#xff09;定义公式代码 SSIMMS-SSIM (Multi Scale Structural Similarity Index Measure,多尺度结构相似性)CSS &#xff08;Contrast-Structure Similarity 对比结构相似度&#xff09;MA…...

CentOS安装sshpass工具-自动化SSH密码认证

sshpass是一个在Linux环境下用于自动化SSH密码认证的工具。 一、功能特点 自动化SSH登录&#xff1a;sshpass允许用户在命令行中直接传递密码&#xff0c;从而无需在SSH连接时手动输入密码。这对于自动化脚本和批处理任务非常有用&#xff0c;因为它可以在非交互式环境下完成…...

js 中 如何获取数组的交集【面试题】

一、数组元素为基本类型&#xff1a;Number、String、等基本类型时 1、使用 Set 和 filter&#xff08;适用于两个数组&#xff09; const intersection (arr1, arr2) > {const set new Set(arr2);return [...new Set(arr1)].filter(item > set.has(item)); };将第二…...

value-key 的作用

在 el-autocomplete 组件中&#xff0c;value-key 是一个非常重要的属性&#xff0c;它用于指定选项对象中作为值的字段名。当选项列表是一个包含多个属性的对象数组时&#xff0c;value-key 能帮助组件明确哪个属性是实际要使用的值。比如&#xff0c;选项列表为 [{id: 01, na…...

Spring MVC:从历史演变到实战入门

1. Java Web的发展历史与MVC模式 1.1 Model I与Model II的演进 Model I&#xff08;JSPJavaBean&#xff09; 作为早期Java Web开发的主流模式&#xff0c;其核心架构如下&#xff1a; graph LR A[客户端] --> B[JSP页面] B --> C{业务逻辑} C --> D[JavaBean] D -…...

Matlab设置表table的表头

用到matlab的table很好用。经常涉及放入数据&#xff0c;读取数据&#xff0c;下面总结常用的知识点。 1. 把不同数据类型放到同一个表中 想把时间类型和数值类型放到统一table中。困扰的点是&#xff0c;我已经知道了表头名称&#xff0c; 如何批量的为表头命名&#xff0c;…...

预测蓝桥杯16届嵌入式省赛客观题

以下是15道蓝桥杯嵌入式省赛客观题预测&#xff0c;每道题均包含**选项列表**、**答案**和**解析**&#xff0c;格式清晰便于快速查阅&#xff1a; 一、预测1 ### **一、STM32G4硬件基础与外设配置** 1. **STM32G431RBT6的Flash和RAM容量分别为&#xff1f;** **选项**&a…...

综合章节:游戏网络化、模组化与深度扩展

模块一&#xff1a;网络功能与玩家数据同步 目标&#xff1a;实现玩家得分上传、全球排行榜展示及云端数据同步。 # network_manager.py&#xff08;网络请求封装&#xff09; import requests import threadingclass NetworkManager:def __init__(self, base_url"http:…...

PostgreSQL:索引与查询优化

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…...

Android Compose 框架的 ViewModel 委托深入剖析(二十)

Android Compose 框架的 ViewModel 委托深入剖析 一、引言 在 Android 开发中&#xff0c;数据的管理和状态的保存是至关重要的。ViewModel 作为 Android 架构组件的一部分&#xff0c;为我们提供了一种在配置更改&#xff08;如屏幕旋转&#xff09;时保存数据和管理 UI 状态…...

android|生成二维码qrcode(android)

1.build.gradle implementation com.google.zxing:core:3.4.1引入zxing库 只是生成的话引入core库就可以了 2.封装方法 import android.graphics.Bitmap; import android.graphics.Color;import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; imp…...

element-plus中el-empty空盒子组件和Collapse 折叠面板组件的使用

一.el-empty空盒子组件的使用 直接复制下面的代码&#xff1a; <el-empty description"description" /> 展示效果&#xff1a; 还可以自定义文字描述&#xff1a; <el-empty description"暂未选择患者"/> 二.Collapse 折叠面板组件的使用 复制…...

Windows 和 Linux 操作系统架构对比以及交叉编译

操作系统与架构兼容性详解 1. 可执行文件格式&#xff1a;PE vs ELF Windows: PE (Portable Executable) 格式 详细解释&#xff1a; PE 格式是 Windows 下的可执行文件标准 包含多个区段&#xff08;Sections&#xff09;&#xff0c;如代码段、数据段、资源段 文件头包含…...

【区块链安全 | 第一篇】密码学原理

文章目录 1.哈希函数1.1 哈希函数的性质1.2 常见哈希算法1.3 Merkle Tree&#xff08;默克尔树&#xff09;1.4 HMAC&#xff08;哈希消息认证码&#xff09; 2. 公钥密码学2.1 对称加密 vs 非对称加密2.2 RSA 算法2.3 ECC&#xff08;椭圆曲线密码学&#xff09;2.4 Diffie-He…...

3.23[A]linux

gedit 是 GNOME 桌面环境下的文本编辑器&#xff0c;类似于 Windows 中的记事本&#xff0c;但功能更强大&#xff0c;支持语法高亮、多文件编辑等特性。它是一个图形化界面的文本编辑器&#xff0c;适合在需要直观编辑文本文件的场景中使用。 gedit 通常用于编辑配置文件、源代…...

AI革命之下的前端将会如何发展?

一、AI 为前端开发带来的变革 &#xff08;一&#xff09;提升开发效率 传统的 Web 前端开发常常面临大量重复性工作&#xff0c;如编写简单表单、布局组件等&#xff0c;这些工作耗时费力且易出错&#xff0c;严重影响开发效率和项目进度。而 AI 的出现&#xff0c;通过自动…...

【2025】基于springboot+vue的农产品商城系统设计与实现(源码、万字文档、图文修改、调试答疑)

项目完整功能以演示视频为准 基于Spring Boot Vue的农产品商城系统设计与实现功能结构图如下&#xff1a; 课题背景 随着互联网的普及和电子商务的快速发展&#xff0c;农产品线上销售成为推动农业现代化和乡村振兴的重要力量。传统的农产品销售模式存在信息不对称、销售渠道单…...

沪深300股指期货的看涨看跌方式是怎样的?

沪深300指数代表了中国A股市场中300家大公司的整体表现。股指期货交易允许老板们预测指数未来的涨跌&#xff0c;并从中获利。 沪深300股指期货基础操作 首先&#xff0c;沪深300股指期货中的看涨操作&#xff1a;老板们可以通过买入沪深300股指期货合约&#xff0c;代码也就是…...

使用selenium来获取数据集

使用selenium来获取数据集 1、下载最新的chrome浏览器与chromedriver.exe 查看chrome的版本,打开谷歌浏览器,点击右上角的三个点,然后点击【帮助】, 点击【关于Google Chrome】 然后去下载同样为134版本号的chromedriver.exe, 网址:https://googlechromelabs.github.…...

MCP(大模型上下文协议)

以下是关于大模型MCP协议&#xff08;Model Context Protocol&#xff09;的详细介绍&#xff0c;综合其定义、技术架构、应用场景及行业影响&#xff1a; 一、定义与核心目标 **MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;**是由Anthropic…...