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

JAVA八股

快速失败(fail-fast)

设计的目的是为了避免在遍历时对集合进行并发修改,从而引发潜在的不可预料的错误。

通过迭代器遍历集合时修改集合: 如果你使用Iterator遍历集合,然后直接使用集合的修改方法(如add()remove()),集合的结构会发生变化,而迭代器并没有同步感知到这些变化,就会抛出ConcurrentModificationException

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String element = iterator.next();if (element.equals("B")) {list.remove(element);  // 修改了集合结构,抛出 ConcurrentModificationException}
}

通过增强型 for 循环遍历集合时修改集合: 增强型 for 循环实际上是基于迭代器的语法糖,因此在遍历过程中如果修改了集合,同样会抛出 ConcurrentModificationException

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");for (String element : list) {if (element.equals("B")) {list.remove(element);  // 抛出 ConcurrentModificationException}
}

如何避免异常

使用迭代器的remove()方法: 如果需要在迭代过程中删除元素,可以使用迭代器自带的remove()方法,它会安全地修改集合,并更新迭代器的状态,不会抛出异常。

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String element = iterator.next();if (element.equals("B")) {iterator.remove();  // 使用迭代器的 remove() 方法,安全移除元素}
}

避免在遍历时修改集合: 如果你必须在遍历时修改集合,可以考虑先将要删除的元素收集到一个临时列表中,遍历完成后再删除它们。

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");List<String> toRemove = new ArrayList<>();
for (String element : list) {if (element.equals("B")) {toRemove.add(element);  // 将要删除的元素暂存}
}
list.removeAll(toRemove);  // 之后统一删除

使用并发集合类: 在多线程环境中,如果多个线程同时对集合进行操作,推荐使用并发集合类,如CopyOnWriteArrayListConcurrentHashMap,它们支持线程安全的修改。

List<String> list = new CopyOnWriteArrayList<>();
list.add("A");
list.add("B");
list.add("C");for (String element : list) {if (element.equals("B")) {list.remove(element);  // 不会抛出异常,因为 CopyOnWriteArrayList 是线程安全的}
}

HashMapHashtable 的区别

  • HashMap:非线程安全,允许null键和null值,效率较高。
  • Hashtable:线程安全,不允许null键和null值,效率相对较低。

 StringBuilder和StringBuffer的区别

synchronized关键字的用法和实现原理?

 用法synchronized可以用于方法或代码块,确保在多线程环境下,某些代码块在同一时间只有一个线程可以执行

synchronized (this) {// 线程安全的代码
}

实现原理synchronized会通过获取对象的监视器锁(Monitor Lock)来实现同步,锁住代码块或方法,保证临界区内的线程安全。

什么是volatile关键字?它有什么作用?

volatile关键字是Java中的一个修饰符,用于保证多线程环境下共享变量的可见性。当一个变量被声明为volatile时,它告诉Java编译器和运行时环境,任何对该变量的读写操作都要直接从主内存中进行,而不是从线程的本地缓存中读取。

写入:如果不使用volatile关键字,线程会将修改的值保存到缓存中,如果使用了volatile关键字,线程会将修改的值刷新到主内存中。保证多线程环境下共享变量的可见性。

读取:如果不使用volatile关键字,线程会从缓存中读取该变量,因为一般线程会将修改的值保存到缓存中。如果使用了volatile关键字,线程就会从主内存中读取修改后的变量值。

  • volatile 保证了变量的可见性,即一个线程对该变量的修改能立即被其他线程看到。
  • volatile 防止了指令重排序,确保变量的读写顺序在并发环境中是安全的。
  • volatile 不保证操作的原子性,对于涉及多个步骤的操作仍然可能需要同步或者使用更高级的并发工具类。

JVM的内存模型是怎样的?堆内存和栈内存的区别?

  • JVM内存模型包括:方法区、堆、虚拟机栈、本地方法栈和程序计数器。
  • 堆内存:用于存储所有的对象,堆是线程共享的
  • 栈内存:用于存储局部变量、方法调用等,栈是线程私有的

JVM中的垃圾回收机制是怎样的?

  • JVM的垃圾回收器采用“分代收集算法”,主要分为年轻代(Eden区、S0/S1区)和老年代。
  • 垃圾回收算法主要包括:
    • 标记-清除算法:标记活跃对象,清除未标记对象。
    • 标记-整理算法:对老年代使用,整理内存空间。
    • 复制算法:对年轻代使用,将存活对象复制到另一区域。

反射

反射(Reflection)是Java语言中的一种机制,允许程序在运行时动态地检查和操作类、接口、方法、属性等信息。通过反射,程序可以在运行时获取类的结构信息,并能够动态地创建对象、调用方法、访问字段等。反射通常用于框架、库开发和动态代理等场景。

反射的作用

  1. 动态获取类的信息:可以在运行时获取类的全限定名、构造方法、字段、方法等信息。
  2. 动态调用方法:在运行时通过反射调用对象的方法,而不需要在编译时确定具体调用的内容。
  3. 动态访问字段:可以访问对象的私有、受保护或公有字段,并且可以对其进行读取或修改。
  4. 动态创建对象:不需要提前知道类的名称,可以在运行时根据名称动态地创建类的实例。

反射的使用

Java中的反射机制主要通过java.lang.reflect包来实现。以下是几个常用的反射类和方法:

  • Class<?>:表示一个类的类对象,可以通过它获取类的元数据。
  • Field:表示类中的字段(成员变量)。
  • Method:表示类中的方法。
  • Constructor<?>:表示类的构造函数。

反射的具体例子

1. 获取类的Class对象

可以通过三种方式获取某个类的Class对象:

  • 通过类的类名Class.forName("类的全限定名")
  • 通过对象对象.getClass()
  • 通过类名.class类名.class
// 通过类名获取
Class<?> clazz1 = Class.forName("com.example.MyClass");// 通过对象获取
MyClass obj = new MyClass();
Class<?> clazz2 = obj.getClass();// 通过类名.class获取
Class<?> clazz3 = MyClass.class;

反射的缺点

  1. 性能开销大:反射涉及到大量的动态类型检查和方法调用,性能相对于直接调用稍差。
  2. 安全性问题:反射允许访问私有字段和方法,可能会破坏封装性。
  3. 编译时检查失效:使用反射时,很多错误会推迟到运行时才会暴露。

常见的设计模式有哪些

 设计模式是为了解决软件开发中常见问题而总结出的可重用解决方案,主要分为创建型模式结构型模式行为型模式三类。

http请求(put post区别) 

  • POST:用于向服务器发送数据,用于创建资源,或者向已存在的资源发送数据。POST 请求通常会导致服务器状态的变化或触发某些动作。

    • 语义上是“添加”(append)数据到资源上。
    • 常用于提交表单数据、上传文件、处理非幂等操作(即操作可能有不同的结果,每次执行结果不同)。
  • PUT:用于在服务器上创建或替换资源。PUT 请求是幂等的,也就是说,重复的 PUT 请求应产生相同的结果。

    • 语义上是“更新”或者“替换”资源。如果资源不存在,则创建资源。
    • 常用于更新某个已知的资源,例如通过 PUT /users/123 更新 ID 为 123 的用户信息。

开启线程的方法 线程的状态 

一、开启线程的方法

1. 继承 Thread

通过继承 Thread 类并重写其中的 run() 方法来定义线程。

步骤:

  1. 创建一个继承自 Thread 类的类。
  2. 重写 run() 方法,将线程执行的代码放入其中。
  3. 创建线程对象并调用 start() 方法启动线程。
class MyThread extends Thread {@Overridepublic void run() {// 线程执行的任务System.out.println("Thread is running...");}
}public class TestThread {public static void main(String[] args) {MyThread t1 = new MyThread();  // 创建线程对象t1.start();  // 启动线程}
}
2. 实现 Runnable 接口

通过实现 Runnable 接口并将其传递给 Thread 类的构造函数。

步骤:

  1. 创建一个实现了 Runnable 接口的类。
  2. 实现 run() 方法,将线程执行的代码放入其中。
  3. 将该 Runnable 对象传递给 Thread 构造器并调用 start() 启动线程。
class MyRunnable implements Runnable {@Overridepublic void run() {// 线程执行的任务System.out.println("Runnable is running...");}
}public class TestRunnable {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);  // 创建线程对象thread.start();  // 启动线程}
}
3. 使用匿名内部类

你可以通过匿名内部类的方式直接创建线程。

public class TestThread {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Anonymous Runnable is running...");}});thread.start();  // 启动线程}
}
 4. 使用 Lambda 表达式

在 Java 8 及以上版本中,使用 Lambda 表达式简化 Runnable 接口的实现。

public class TestThread {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("Lambda Runnable is running...");});thread.start();  // 启动线程}
}

二、查看线程的状态

Java 提供了一些方法和枚举来检查线程的状态。可以通过调用 Thread 类的方法来获取线程的当前状态。

1. 线程状态枚举(Thread.State

Thread.State 是枚举类型,它定义了线程的六种状态:

  • NEW:线程对象已经创建,但尚未调用 start() 方法。
  • RUNNABLE:线程正在 Java 虚拟机中运行。
  • BLOCKED:线程被阻塞,正在等待监视器锁(同步锁)。
  • WAITING:线程无限期等待另一个线程执行特定操作。
  • TIMED_WAITING:线程在等待,超时后会被唤醒。
  • TERMINATED:线程已完成执行。
2. 获取线程状态的方法

使用 Thread 类中的 getState() 方法来查看线程的状态。

Runnable和Callable的区别?

1. Runnable 详细说明:

  • Runnable 接口定义了一个 run() 方法,用于封装并发任务。它不返回任何结果,也不会抛出任何受检异常。
    public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable is running");}
    }public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();  // 启动线程,执行run()方法}
    }
    

2. Callable 详细说明:

  • Callable 接口定义了一个 call() 方法,可以返回任务的执行结果,并且可以抛出异常。通常与 ExecutorService 结合使用。
  • 返回的结果可以通过 Future 对象来获取。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "Callable result";}
}public class Main {public static void main(String[] args) throws InterruptedException, ExecutionException {ExecutorService executor = Executors.newSingleThreadExecutor();Future<String> future = executor.submit(new MyCallable());System.out.println(future.get());  // 获取 Callable 的返回值executor.shutdown();}
}

线程池的工作原理?

线程池通过管理一组线程来提高应用程序的性能和资源利用率。通过合理的任务队列和线程管理策略,线程池可以高效地处理并发任务,并在多线程环境中保持系统的稳定性。

1. 线程池的组件

  • 核心线程:线程池初始化时创建的线程,始终保持在池中。
  • 最大线程:线程池可以创建的最大线程数量,超出这个数量的任务会被放入任务队列。
  • 任务队列:存放待执行任务的队列,可以是不同类型的队列(如无界队列、有界队列等)。
  • 空闲线程存活时间:核心线程以外的线程在没有任务时的存活时间,超出这个时间会被销毁。

2. 工作流程

a. 线程池的创建

线程池通过 ExecutorsThreadPoolExecutor 创建,设定核心线程数、最大线程数和任务队列类型。

b. 任务提交
  • 使用 submit()execute() 方法将任务提交到线程池。
  • 提交任务时,线程池会首先检查当前正在运行的线程数量。
c. 线程的处理
  1. 如果运行的线程少于核心线程

    • 创建新线程来处理任务,并立即执行。
  2. 如果运行的线程已达到核心线程数

    • 将任务放入任务队列。
    • 如果队列已满,且当前线程数小于最大线程数,则创建新线程来处理任务。
  3. 如果运行的线程已达到最大线程数

    • 根据任务队列的类型进行处理(丢弃、抛出异常、执行某种策略等)。
d. 任务执行
  • 线程从任务队列中获取任务并执行。
  • 执行完毕后,线程返回线程池,准备接收新的任务。
e. 线程的销毁
  • 如果空闲线程的数量超过核心线程数,并且超过了指定的空闲存活时间,则会被销毁。
  • 当线程池关闭时,未完成的任务将根据关闭策略(如 shutdown()shutdownNow())进行处理。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService threadPool = Executors.newFixedThreadPool(3);// 提交任务for (int i = 1; i <= 10; i++) {final int taskId = i;threadPool.submit(() -> {System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());try {// 模拟任务执行时间Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Task " + taskId + " is completed by " + Thread.currentThread().getName());});}// 关闭线程池threadPool.shutdown();}
}

List Set Map的区别?

  • List:适合需要按顺序访问元素的场景,如保存用户列表、待办事项等。
  • Set:适合需要确保元素唯一的场景,如存储用户的邮箱地址、商品的ID等。
  • Map:适合存储键值对关系的场景,如存储用户信息(用户名和对应的用户对象)、产品ID与产品详情的关系等。

B+树和红黑树的区别,哪个效果更好,为什么?

索引:帮助MySQL高效获取数据的排好序数据结构,如二叉树,红黑树,Hash表,B-Tree

红黑树是一种二叉搜索树,当左右子树高度不平衡是会进行调整

B+树是一种多路搜索树,

  • 非叶子节点不存储数据,只存储索引,可以放更多的索引(前一层存放的是下一层索引的第一个值)
  • 叶子节点包含所有索引字段
  • 叶子节点用指针链接,提高区间访问的性能

​ B+树的效果更好,因为高度更低,查询效率更高。

常见的字符串操作

public class StringExample {public static void main(String[] args) {String str = " Hello, World! ";// 1. 字符串长度System.out.println("Length: " + str.length());// 2. 去除空格System.out.println("Trimmed: '" + str.trim() + "'");// 3. 转换为大写System.out.println("Uppercase: " + str.toUpperCase());// 4. 子字符串System.out.println("Substring: " + str.substring(7));// 5. 替换字符System.out.println("Replaced: " + str.replace("World", "Java"));// 6. 分割字符串String[] parts = str.split(", ");for (String part : parts) {System.out.println("Part: " + part);}// 7. 格式化字符串String formatted = String.format("Name: %s, Age: %d", "John", 30);System.out.println("Formatted: " + formatted);}
}

char和varchar的区别 

数据库的sql失效一般有哪些场景

SQL 失效通常指的是在数据库中,原本可以使用的 SQL 查询突然变得无法执行或效率降低。以下是一些常见的场景:

  1. 数据库结构变化

    • 表结构、索引或数据类型的更改,可能导致原有查询计划失效。
  2. 统计信息过时

    • 数据库优化器依赖统计信息来生成执行计划。如果统计信息未更新,可能导致选择不合适的查询计划。
  3. 参数变化

    • 使用参数化查询时,不同参数值可能导致生成不同的执行计划,某些计划可能在某些参数下失效。
  4. 索引失效

    • 索引被删除、修改或变得不再适用,可能导致查询效率显著下降。
  5. 数据分布变化

    • 数据量或数据分布发生变化,例如数据倾斜,可能导致原有的查询计划不再高效。
  6. 锁竞争或阻塞

    • 由于高并发导致锁竞争或阻塞,可能导致原本顺利执行的 SQL 变得缓慢或失效。
  7. 缓存失效

    • 查询结果缓存失效,导致相同的查询需要重新执行而不是从缓存中获取结果。
  8. 数据库配置变更

    • 数据库参数配置或硬件资源的变化可能影响查询的执行计划。
  9. 代码逻辑修改

    • 应用程序中 SQL 查询的逻辑改变,可能导致执行效率下降。

面向对象和面向过程的区别

类的加载机制?

  • 加载 (Loading)

    • .class 文件中读取字节码,并将其加载到内存中。加载器会根据类的名称和路径查找对应的 .class 文件。
  • 链接 (Linking)

    • 验证 (Verification):检查加载的字节码是否符合 Java 虚拟机规范,确保安全性。
    • 准备 (Preparation):为类变量分配内存,并设置其默认值。
    • 解析 (Resolution):将常量池中的符号引用转换为直接引用,即确定实际的内存地址。
  • 初始化 (Initialization)

    • 执行类的静态初始化块和静态变量的初始化,设置变量的实际值。这是类加载的最后一步。

Java 中的类加载器主要包括以下几种:

  • 引导类加载器 (Bootstrap ClassLoader)

    • 负责加载 Java 核心类库,如 java.lang.*java.util.* 等。
  • 扩展类加载器 (Extension ClassLoader)

    • 负责加载 JRE 的扩展库(通常在 lib/ext 目录中)。
  • 应用类加载器 (Application ClassLoader)

    • 负责加载用户类路径(classpath)下的类,包括用户自定义的类。

3. 类加载的双亲委派机制

  • 在类加载过程中,类加载器遵循双亲委派模型,即一个类加载器在尝试加载类时,会首先将请求委派给它的父类加载器。如果父加载器无法加载该类,才会由当前加载器进行加载。这种机制可以防止类的重复加载和冲突。

获取一个class对象的方式?

可以通过三种方式获取某个类的Class对象:

  • 通过类的类名Class.forName("类的全限定名")
  • 通过对象对象.getClass()
  • 通过类名.class类名.class
// 通过类名获取
Class<?> clazz1 = Class.forName("com.example.MyClass");// 通过对象获取
MyClass obj = new MyClass();
Class<?> clazz2 = obj.getClass();// 通过类名.class获取
Class<?> clazz3 = MyClass.class;

如何获得类的属性?

1. 通过getter方法获取属性

这是最常见的方式,通常会在类中为每个属性定义相应的getter方法,供外部代码调用。

public class Person {private String name;private int age;// Getter methodspublic String getName() {return name;}public int getAge() {return age;}
}public class Main {public static void main(String[] args) {Person person = new Person();person.getName();  // 获取属性 nameperson.getAge();   // 获取属性 age}
}

2. 通过反射机制获取属性

Java的反射机制允许我们在运行时获取对象的属性,而不需要直接调用getter方法。通过反射,可以动态地获取和修改类的属性,即使这些属性是私有的。

import java.lang.reflect.Field;public class Person {private String name = "John";private int age = 30;
}public class Main {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {Person person = new Person();// 获取属性Field nameField = person.getClass().getDeclaredField("name");nameField.setAccessible(true); // 设置访问权限String name = (String) nameField.get(person);Field ageField = person.getClass().getDeclaredField("age");ageField.setAccessible(true);int age = (int) ageField.get(person);System.out.println("Name: " + name + ", Age: " + age);}
}

3. 通过java.beans.Introspector获取属性

Java中还提供了Introspector类,可以通过内省机制来获取对象的属性信息。它主要用于Java Beans,提供了对类的属性、方法的描述。

​
import java.beans.Introspector;
import java.beans.PropertyDescriptor;public class Person {private String name = "John";private int age = 30;// Getters and Setterspublic String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}public class Main {public static void main(String[] args) throws Exception {Person person = new Person();for (PropertyDescriptor pd : Introspector.getBeanInfo(Person.class).getPropertyDescriptors()) {if (pd.getReadMethod() != null && !"class".equals(pd.getName())) {System.out.println(pd.getName() + ": " + pd.getReadMethod().invoke(person));}}}
}​
// 使用 StringBuilder
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
String result = sb.toString();// 使用 StringBuffer
StringBuffer sbf = new StringBuffer();
sbf.append("Hello");
sbf.append(" ");
sbf.append("World");
String result2 = sbf.toString();

springboot的多环境配置文件是怎么区分的

在 Spring Boot 中,多环境配置文件通常通过不同的配置文件和 spring.profiles.active 属性来区分。

1. 创建配置文件

src/main/resources 目录下,你可以创建不同的配置文件,例如:

  • application.properties(默认配置)
  • application-dev.properties(开发环境)
  • application-test.properties(测试环境)
  • application-prod.properties(生产环境)

2. 配置 application.properties

application.properties 中,可以指定活动的配置文件,例如:

spring.profiles.active=dev

3. 运行时指定活动配置

你可以在启动应用程序时通过命令行参数指定活动的配置文件。例如:

java -jar your-app.jar --spring.profiles.active=prod

4. 使用环境变量

你也可以通过设置环境变量来指定活动的配置文件:

export SPRING_PROFILES_ACTIVE=dev

5. 访问配置属性

在代码中,可以使用 @Value 注解或 @ConfigurationProperties 注解来访问不同环境下的配置属性:

@Value("${some.property}")
private String someProperty;

6. 配置优先级

  • application.properties 是基础配置。
  • 环境特定的配置文件(如 application-dev.properties)会覆盖基础配置。
  • 可以根据需要添加其他特定于环境的配置。

TCP和UDP的区别

相关文章:

JAVA八股

快速失败&#xff08;fail-fast&#xff09; 设计的目的是为了避免在遍历时对集合进行并发修改&#xff0c;从而引发潜在的不可预料的错误。 通过迭代器遍历集合时修改集合&#xff1a; 如果你使用Iterator遍历集合&#xff0c;然后直接使用集合的修改方法&#xff08;如add(…...

关于武汉芯景科技有限公司的限流开关芯片XJ6288开发指南(兼容SY6288)

一、芯片引脚介绍 1.芯片引脚 二、系统结构图 三、功能描述 1.EN引脚控制IN和OUT引脚的通断 2.OCB引脚指示状态 3.过流自动断开...

指令:计算机的语言(五)

2.9 人机交互 ASCII与二进制 对应表略 字节转移指令 lbu&#xff1a;加载无符号字节&#xff0c;从内存中加载1个字节&#xff0c;放在寄存器最右边8位。 sb&#xff1a;存储字节指令&#xff0c;从寄存器的最右边取1个字节并将其写入内存。 复制1个字节顺序如下&#xf…...

C#笔记(1)

解决方案&#xff1a; 【1】组织项目&#xff1a;把项目放在放在一个解决方案中&#xff0c;统一开发&#xff0c;统一编译。 【2】管理项目&#xff1a;开发中的任何问题&#xff0c;在统一编译过程中&#xff0c;都能随时发现。也可以添加第三方的库文件。 命名空间: 命名空…...

SSDF攻击、防御与展望

摘要&#xff1a; 随着无线通信业务的不断发展&#xff0c;频域也越来越成为了一种珍贵的稀缺资源&#xff0c;与此同时&#xff0c;相应的无线电安全问题层出不穷&#xff0c;为无线通信造成了十分恶劣的影响&#xff0c;本文从深入理解认知无线电安全开始&#xff0c;对一些典…...

MedMamba代码解释及用于糖尿病视网膜病变分类

MedMamba原理和用于糖尿病视网膜病变检测尝试 1.MedMamba原理 MedMamba发表于2024.9.28&#xff0c;是构建在Vision Mamba基础之上&#xff0c;融合了卷积神经网的架构&#xff0c;结构如下图&#xff1a; 原理简述就是图片输入后按通道输入后切分为两部分&#xff0c;一部分走…...

单点登录的要点

单点登录&#xff08;SSO&#xff09;是一种身份验证服务&#xff0c;它允许用户使用一组凭据登录一次&#xff0c;然后在多个应用程序中访问其他应用程序而无需重新进行身份验证。这样&#xff0c;用户只需一次登录即可访问整个应用生态系统&#xff0c;提高了用户体验并简化了…...

linux线程 | 一点通你的互斥锁 | 同步与互斥

前言&#xff1a;本篇文章主要讲述linux线程的互斥的知识。 讲解流程为先讲解锁的工作原理&#xff0c; 再自己封装一下锁并且使用一下。 做完这些就要输出一堆理论性的东西&#xff0c; 但博主会总结两条结论&#xff01;&#xff01;最后就是讲一下死锁。 那么&#xff0c; 废…...

全栈开发小项目

用到的技术栈&#xff1a; nodejswebpackknockoutmongodbPM2rabbitmq 以下是一个综合指南&#xff0c;展示如何将 Node.js、Webpack、Knockout.js、MongoDB、PM2 和 RabbitMQ 集成到一个项目中。 我们将在这一项目中添加 RabbitMQ&#xff0c;用于处理消息队列。这对于任务分…...

批处理一键创建扫描仪桌面打开快捷方式图标 简单直接有效 扫描文档图片的应急策略

办公生活中&#xff0c;我们在安装完多功能一体机的打印驱动之后&#xff0c;找不到扫描文件的地方&#xff0c;如果驱动程序安装正确&#xff0c;我们可以用系统自带的扫描仪程序调用这种打印机或复印机的扫描程序即可&#xff0c;它在电脑系统中的位置一般是&#xff1a;C:\W…...

【服务器知识】Tomcat简单入门

文章目录 概述Apache Tomcat 介绍主要特性版本历史使用场景 核心架构Valve机制详细说明请求处理过程 Tomcat安装Windows系统下Tomcat的安装与配置&#xff1a;步骤1&#xff1a;安装JDK步骤2&#xff1a;下载Tomcat步骤3&#xff1a;解压Tomcat步骤4&#xff1a;配置环境变量&a…...

【前端】Matter:过滤与高级碰撞检测

在物理引擎中&#xff0c;控制物体的碰撞行为是物理模拟的核心之一。Matter.js 提供了强大的碰撞检测机制和碰撞过滤功能&#xff0c;让开发者可以控制哪些物体能够相互碰撞&#xff0c;如何处理复杂的碰撞情况。本文将详细介绍 碰撞过滤 (Collision Filtering) 与 高级碰撞检测…...

wps图标没有坐标轴标题怎么办?wps表格不能用enter下怎么办?

目录 wps图标没有坐标轴标题怎么办 一、在WPS PPT中添加坐标轴标题 二、在WPS Excel中添加坐标轴标题 wps表格不能用enter下怎么办 一、检查并修改设置 二、检查单元格保护状态 三、使用快捷键实现换行 wps图标没有坐标轴标题怎么办 一、在WPS PPT中添加坐标轴标题 插入…...

在ESP-IDF环境中如何进行多文件中的数据流转-FreeRTOS实时操作系统_流缓存区“xMessageBuffer”

一、建立三个源文件和对应的头文件 建立文件名&#xff0c;如图所示 图 1-1 二、包含相应的头文件 main.h 图 2-1 mess_send.h mess_rece.h和这个中类似,不明白的大家看我最后面的源码分享 图2-2 三、声明消息缓存区的句柄 大家注意&#xff0c;在main.c中定义的是全局变…...

ConcurrentLinkedQueue适合什么样的使用场景?

ConcurrentLinkedQueue 是 Java 中一种无界线程安全的队列&#xff0c;适合多线程环境中的高并发场景。以下是一些它特别适合的使用场景&#xff1a; 1. 高频读操作&#xff0c;低频写操作 ConcurrentLinkedQueue 对于实际应用中读操作相对频繁&#xff0c;写操作较少的场景非…...

C语言 | Leetcode C语言题解之第480题滑动窗口中位数

题目&#xff1a; 题解&#xff1a; struct Heap {int* heap;int heapSize;int realSize;bool (*cmp)(int, int); };void init(struct Heap* obj, int n, bool (*cmp)(int, int)) {obj->heap malloc(sizeof(int) * (n 1));obj->heapSize 0;obj->cmp cmp; }bool c…...

LabVIEW开发如何实现降维打击

在LabVIEW开发中实现“降维打击”可以理解为利用软件优势和高效工具来解决复杂的问题&#xff0c;将多维度、多层次的技术简化为容易操作和管理的单一维度&#xff0c;达到出其不意的效果。以下是几种关键策略&#xff1a; 1. 模块化设计与封装 将复杂系统分解为若干模块&…...

docker 文件目录迁移

文章参考 du -hs /var/lib/docker/ 命令查看磁盘使用情况。 du -hs /var/lib/docker/docker system df命令&#xff0c;类似于Linux上的df命令&#xff0c;用于查看Docker的磁盘使用情况: rootnn0:~$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 7 2 122.2…...

Markdown 标题

Markdown 标题 Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式化的HTML代码。Markdown 的语法简洁明了,广泛用于撰写文档、博客文章、笔记等。本文将详细介绍 Markdown 的标题语法及其在文档中的应用。 Markdown 标题语法 在…...

【动手学电机驱动】TI InstaSPIN-FOC(5)Lab04 力矩控制

TI InstaSPIN-FOC&#xff08;1&#xff09;电机驱动和控制测试平台 TI InstaSPIN-FOC&#xff08;2&#xff09;Lab01 闪灯实验 TI InstaSPIN-FOC&#xff08;3&#xff09;Lab03a 测量电压电流漂移量 TI InstaSPIN-FOC&#xff08;4&#xff09;Lab02b 电机参数辨识 TI Insta…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...