java面试题

1.string,stringBuilder,stringBuffer 区别?

三者共同之处:都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数被参数修改影响到其他的应用。

StringBuffer是线程安全,可以不需要额外的同步用于多线程中;

StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;

StringBuffer与StringBuilder两者共同之处:可以通过append、indert进行字符串的操作。

String实现了三个接口:Serializable、Comparable、CarSequence

StringBuilder只实现了两个接口Serializable、CharSequence,相比之下String的实例可以通过compareTo方法进行比较,其他两个不可以。

1、首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String

String最慢的原因:String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。以下面一段代码为例:

  1. 再来说线程安全

在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的

如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

(一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞)

  1. 总结一下

String:适用于少量的字符串操作的情况

StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

2.hashmap内部存储结构

HashMap是一种常见的 Java 数据结构,它使用散列函数将键映射到数组中的索引,从而实现快速插入、删除和查找操作。

HashMap 内部存储结构如下:

  1. 散列表:是一个数组,用于存储键值对。
  2. 散列函数:是一个函数,用于将键映射到数组中的索引。
  3. 桶:是一个链表,用于存储键值对。当多个键映射到同一个索引时,它们将被存储在同一个桶中。
  4. 链表:是一个链表,用于存储桶中的键值对。链表可以使 HashMap 在冲突的情况下仍然能够保证对键的快速查找。

HashMap 的散列函数确保了散列表中的索引是均匀分布的,并且可以使用链表处理散列冲突。这使得 HashMap 能够在大多数情况下实现 O(1) 的时间复杂度。

但是,在极端情况下,某些索引可能会导致链表变得很长,导致查找的时间复杂度退化到 O(n)。因此,选择合适的散列函数和调整散列表的大小是非常重要的,以确保 HashMap 的效率。

3.集合有个迭代器,为什么要设计出这个迭代器?

首先使用迭代器适用性强,因为如果用for循环遍历,需要事先知道集合的数据结构,而且当换了一种集合的话代码不可重用要修改,不符合开闭原则。而Iterator是用同一种逻辑来遍历集合。其次使用Iterator可以在不了解集合内部数据结构的情况下直接遍历,这样可以使得集合内部的的数据不暴露。

在单机环境下并发控制,java有哪些手段?
  • 同步代码块

  • CAS自旋

  • 阻塞队列,令牌桶等

  • 信号量Semaphore

  1. synchronized关键字:Java 中的 synchronized 关键字可以在同步代码块中使用,可以保证同一时刻只有一个线程执行该代码块。
  2. Lock接口:Java 中的 Lock 接口提供了更丰富的锁定功能,比如说读写锁,可重入锁等。
  3. java.util.concurrent.locks:Java 中的 java.util.concurrent.locks 包提供了多种锁类型,比如说 ReentrantLock,ReentrantReadWriteLock,Semaphore,CountDownLatch 等。
  4. Atomic类:Java 中的 Atomic 类提供了一种线程安全的类型,可以确保原子性的操作,比如说 AtomicInteger 等。
  5. volatile关键字:Java 中的 volatile 关键字可以保证该变量的可见性和有序性,但是不能保证原子性。
4.多线程创建的方式有哪几种?

1.继承Thread类,重写run方法
2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
3.通过Callable和FutureTask创建线程
4.通过线程池创建线程

前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果。
后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中。

5.怎么防止表单重复提交(服务器端)

https://blog.csdn.net/xin_shou123/article/details/115472213

1)利用Session防止表单重复提交

具体的做法:
1、获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌)。

2、将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端。

3、服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
2)判断请求url和数据是否和上一次相同

推荐,非常简单,页面不需要任何传入,只需要在验证的controller方法上写上自定义注解即可

写好自定义注解

3)利用Spring AOP和redis的锁来实现防止表单重复提交

主要是利用了redis的分布式锁机制

第一次点击提交表单,判断到当前的token还没有上锁,即给该token上锁。如果连续点击提交,则提示不能重复提交,当上锁的那次操作执行完,redis释放了锁之后才能继续提交。

6.SpringAOP

1.Spring AOP 的工作原理是什么?

Spring AOP 基于动态代理实现,在代码执行期间动态地在目标对象和切面之间建立关联。在目标对象的方法执行时,Spring AOP 会先在切面中查找是否有相应的通知方法,如果有,则先执行切面中的通知方法,然后再执行目标对象的方法。

2.Spring AOP 支持哪些通知类型?

Spring AOP 支持以下通知类型:前置通知、后置通知、返回通知、异常通知、环绕通知。

3.什么是切点?

切点是 AOP 中定义了切入点的地方,也就是要被通知的方法。切点是通过表达式定义的,使用切点表达式可以指定在那些方法上应用通知。

4.什么是连接点?

连接点是在应用程序执行期间,程序能够到达的实际方法调用的位置。连接点是切点的实际位置。

5.Spring AOP 支持哪些切入点表达式?

Spring AOP 支持以下几种切入点表达式:

  • 基于方法名的表达式,例如 execution(* com.example.service.*.*(..))
  • 基于注解的表达式,例如 @target(org.springframework.transaction.annotation.Transactional)
  • 基于 AspectJ 表达式,例如 within(com.example.service.*)

6.什么是通知?

通知是在切点的方法执行前或执行后要执行的代码。通知是切面的核心部分,用于实现切面的功能。

7.什么是织入?

织入是把切面和目标对象关联起来的过程。织入可以在编译期间或运行期间完成,在 Spring AOP 中是在运行期间完成的。

7.批量往mySql数据库导入1000万条数据有什么思路?
  1. 使用 LOAD DATA INFILE 语句:该语句可以快速将文本文件中的数据导入到 MySQL 数据库。
  2. 使用 mysqlimport 工具:该工具是 mysql 的一个命令行工具,可以快速导入大量数据到 MySQL 数据库。
  3. 使用 JDBC 批处理:您可以使用 JDBC API 中的批处理功能,一次插入多行数据。
  4. 分批次导入:可以把数据分成多个批次,分别导入。这样可以降低对数据库性能的影响。

具体使用哪种方法,可能要取决于您的硬件资源、数据量以及其他需求。

此外,在导入数据之前,您还可以考虑优化数据库结构和索引,以提高导入数据的速度。

8.项目中打日志的框架,错误日志具体怎么配置?
9.多线程同步实现方式?
  1. synchronized 关键字:通过使用 synchronized 关键字来保护代码块,从而实现多线程同步。
  2. Lock 接口:比 synchronized 关键字更灵活,提供了更多的控制。
  3. ReentrantLock 类:是 Lock 接口的实现类,提供了与 synchronized 关键字相似的同步能力。
  4. ReadWriteLock 接口:是一种特殊类型的锁,用于读多写少的场景。
  5. Semaphore 类:是一种控制访问线程数量的锁,它通过控制访问次数来实现同步。
  6. CountDownLatch 类:允许一个或多个线程等待其他线程完成操作。

以上是常用的多线程同步实现方式,选择合适的方式需要根据具体情况进行判断。

10.hashcode的作用?

hashCode() 方法是 Java 中 Object 类的一个方法,它主要用于生成对象的散列码。

散列码是对象的唯一标识,通常是一个整数。在 Java 中,hashCode() 方法通常用于以下场景:

  1. 集合(如 HashMap、HashSet 等):通过对象的散列码快速查找元素。
  2. 缓存:使用散列码存储缓存对象,从而实现快速访问。
  3. 判断两个对象是否相等:如果两个对象的散列码相同,则认为它们是相等的。

在实现 hashCode() 方法时,需要注意以下几点:

  1. hashCode() 方法返回的散列码应该是对象的唯一标识,不能改变。
  2. 如果两个对象相等,则它们的散列码必须相等。
  3. 如果两个对象不相等,则它们的散列码不一定不相等。

在 Java 中,通常使用散列函数(hash function)生成散列码,以保证散列码的唯一性和分布均匀性。

返回当前对象的hash值,hash值是每个对象特有的一串数字不可重复,类似于每个对象的身份证

11.异常:error和exception有什么区别?

ErrorException 都是 Java 中的异常,但它们有一些重要的区别:

  1. 致命性:Error 是一种致命性错误,不能被捕获和处理。而 Exception 可以被捕获和处理。
  2. 范围:Error 通常是 Java 虚拟机(JVM)内部错误,如内存溢出错误(OutOfMemoryError)、类加载错误(ClassFormatError)等。而 Exception 可以是程序中的逻辑错误,如文件未找到异常(FileNotFoundException)、数组越界异常(ArrayIndexOutOfBoundsException)等。
  3. 可恢复性:Error 通常是不可恢复的错误,程序无法继续运行。而 Exception 可以被捕获和处理,程序可以继续运行。
  4. 编码习惯:通常不需要显式地处理 Error,因为它是致命性错误,程序无法继续运行。而对于可恢复的 Exception,程序员应该尽量处理,以保证程序的稳定性和可靠性。
12.redis,说一个实际应用的场景和数据类型?

Redis 是一种开源的内存数据存储系统,支持多种数据类型。Redis 由于其数据存储在内存中,读写速度快,适用于处理高并发场景。

以下是 Redis 在实际应用中的一个场景:

场景:网站访问量统计

数据类型:Redis 的字符串(String)类型

在这个场景中,我们需要对网站的访问量进行统计,并保存在 Redis 中。我们可以使用 Redis 的字符串类型对网站的访问量进行记录,并定期把数据存入数据库进行持久化存储。

使用 Redis 进行统计,可以在大幅提高系统的处理效率,防止因为数据库读写过多造成的系统压力过大等问题。

13.SpringAOP在项目的实际应用?

Spring AOP(面向切面编程)是一种在 Java 应用程序中实现分布式面向切面的编程的技术。它可以在不修改代码的情况下,给现有的方法增加额外的功能。

Spring AOP 在实际项目中的实际应用如下:

  1. 日志记录:使用 AOP 可以简单方便地记录方法的执行情况,便于跟踪和分析。
  2. 权限控制:AOP 可以在方法调用前后进行权限验证,确保没有授权的用户无法访问系统。
  3. 事务管理:AOP 可以简化事务管理的复杂性,统一地对数据库进行事务处理,保证数据的一致性。
  4. 缓存管理:AOP 可以帮助实现缓存的管理,缓存数据的读写操作,提高系统的效率。
  5. 性能监控:AOP 可以帮助实现系统的性能监控,例如记录方法的执行时间,帮助分析系统的性能瓶颈。
14.mysql索引失效的场景,能介绍一下?
  1. 过多的 NULL 值:如果数据表中有过多的 NULL 值,那么 MySQL 就不会使用索引。
  2. 过长的索引:如果索引字段的长度过长,MySQL 可能不会使用该索引。
  3. 类型不匹配:如果查询字段与索引字段类型不匹配,那么 MySQL 就不会使用该索引。
  4. 不符合索引使用条件:MySQL 仅在满足索引使用条件的情况下才会使用索引。例如,在进行大于、小于或不等于操作时,MySQL 不会使用索引。
  5. 使用不当的查询语句:在查询语句中使用不当的操作,例如在复杂的子查询或连接操作中,MySQL 可能不会使用索引。
15.数据库根据什么条件去创建索引?怎么去建索引。

频繁查询的字段:如果某个字段经常被查询,那么就应该在该字段上创建索引。

经常作为排序或分组字段的字段:如果某个字段经常被用于排序或分组操作,那么就应该在该字段上创建索引。

经常作为连接条件的字段:如果某个字段经常被用于数据表之间的连接操作,那么就应该在该字段上创建索引。

外键字段:如果某个字段是外键,那么就应该在该字段上创建索引。

怎么去建索引?

在 MySql 中,可以使用以下语句创建索引:

Copy code
CREATE INDEX index_name
ON table_name (column1, column2, ...);

index_name:索引的名称
table_name:数据表的名称
column1, column2, …:需要在上面创建索引的字段。
需要注意的是,在创建索引时,应该选择合适的索引类型(如 B-Tree、Hash 等),并确保索引字段数据分布均匀,以保证索引的效率。

16.什么是事务?

事务是数据库管理系统中的一种重要机制,用于保证数据的完整性和一致性。

事务是一组逻辑操作单元,包含多个数据库操作,这些操作要么全部完成,要么全部不完成。事务是一个原子性的操作,它要么全部成功,要么全部失败。

事务的特性**(ACID)**:

  1. 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的所有操作要么全部完成,要么全部不完成。
  2. 一致性(Consistency):事务必须使数据库从一个一致性状态变到另一个一致性状态。
  3. 隔离性(Isolation):多个事务之间不能相互影响,每个事务都有自己的独立空间。
  4. 持久性(Durability):事务完成后,对数据库的修改是永久性的。

事务的实现通常需要使用数据库管理系统的事务支持,例如 MySql 中的 InnoDB 存储引擎。在代码中,可以使用数据库的事务 API 来控制事务的开始、提交和回滚。

17.spring事务没生效?

如果 Spring 事务没有生效,可能是由于以下几个原因:

1.没有开启事务支持:如果没有启用事务支持,事务将不会生效。确保在配置文件中启用事务支持,例如:

<tx:annotation-driven transaction-manager="transactionManager" />

2.配置事务管理器错误:确保已正确配置事务管理器,并且关联到正确的数据源。

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
</bean>

3.没有在相应的方法或类上添加事务注解:确保已在需要事务的方法或类上添加事务注解,例如:

@Transactional
public void updateData() {
  // method body
}

4.事务配置不正确:确保事务配置正确,包括隔离级别、传播行为等。

如果在解决这些问题后仍然无法生效,可以尝试记录日志以进一步了解问题的原因。

18.ArrayList和LinkedList的区别?

ArrayList低层是用数组存储的,线程不安全,运行效率高,查询快,增删慢

LinkedList低层是用双向链表存储的,适合频繁的插入和删除操作,查询慢

19.高并发情况下,用到list集合,怎么处理?

在高并发情况下使用 List 集合时,可能存在线程不安全问题。为了避免这种情况,最好使用线程安全的集合,例如:java.util.concurrent 包中的 CopyOnWriteArrayList。

另外,在高并发情况下,还可以使用同步技术,例如:synchronized 关键字或 ReentrantLock 类,来保证 List 的线程安全。

示例代码:

private final List<String> list = new CopyOnWriteArrayList<>();

public void addData(String data) {
  list.add(data);
}

public List<String> getList() {
  return list;
}

需要注意的是,使用同步技术或线程安全的集合可能会导致性能问题,因此在实际使用时需要综合考虑。

20.hashmap底层数据结构?1.7,1.8 ,扩容机制?加key-value下标怎么确定?hash冲突该怎么解决

HashMap的底层数据结构是哈希表,其主要原理是通过哈希算法将键映射到数组中的桶(bucket),桶内的元素形成链表。

在 Java 1.7 版本中,HashMap 内部数组是一个 Entry 类型的数组,它实现了链表,当链表长度大于 8 时,该链表会被转换为红黑树,以提高查询性能。

在 Java 1.8 版本中,HashMap 内部数组的类型从 Entry 改为 Node,并且在桶中的元素数量较多时使用红黑树而不是链表,以提高查询性能。

当 HashMap 容量不足以存储元素时,会扩容。默认情况下,容量会扩大到原来的两倍,并且在扩容后重新计算元素的位置。

在将键值对插入 HashMap 中时,首先会对键进行哈希,然后根据哈希值和数组长度计算出数组的下标。如果该下标已有元素,则可能存在哈希冲突,此时 HashMap 会将冲突的键值对插入链表或红黑树中,以保证键的唯一性。

key的hash值与数组长度按位与来确定数组下标

21.hashset怎么保证数据不可重复?

低层实现是hashmap

22.==与equals区别?重写equals,为什么要重写hashcode?

对于对象集合的判重,如果一个集合含有10000个对象实例,仅仅使用equals()方法的话,那么对于一个对象判重就需要比较10000次,随着集合规模的增大,时间开销是很大的。但是同时使用哈希表的话,就能快速定位到对象的大概存储位置,并且在定位到大概存储位置后,后续比较过程中,如果两个对象的hashCode不相同,也不再需要调用equals()方法,从而大大减少了equals()比较次数。 所以从程序实现原理上来讲的话,既需要equals()方法,也需要hashCode()方法。那么既然重写了equals(),那么也要重写hashCode()方法,以保证两者之间的配合关系。

23.hashmap和hashtable有什么区别?底层数据结构?hashmap是线程安全的吗?

hashmap线程不安全,效率高,可以存储null的key和value

hashtable线程安全,效率低,不可以存储null的key和value

LinkedHashMap,保证在遍历集合元素时,按照添加顺序遍历,因为有指针指向前一个元素和后一个元素,用于频繁遍历操作

TreeMap,保证按照添加的key-value进行排序,实现排序遍历,按照key的排序,底层是红黑树

在什么情况下会使用多线程?创建多线程有哪些方式?有什么区别?

底层数据结构

HashMap:1.7之前数组+链表

1.8 数组+链表+红黑树

24.hashcode的作用?

返回当前对象的hash值,hash值是每个对象特有的一串数字不可重复,类似于每个对象的身份证

25.我对IoC**(控制反转)和DI(依赖注入)**的理解

什么是IOC?低层是如何实现的,这样设计有什么好处?

在平时的java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,在没有使用Spring的时候,每个对象在需要使用他的合作对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机是由自己把控的,而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起,而使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。

所以控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。

这是我对Spring的IoC**(控制反转)的理解。DI(依赖注入)**其实就是IOC的另外一种说法,DI是由Martin Fowler 在2004年初的一篇论文中首次提出的。他总结:控制的什么被反转了?就是:获得依赖对象的方式反转了。

什么是 IoC?

IoC (Inversion of Control) 是一种设计模式,它通过将对象之间的依赖关系从代码中抽离出来,把对象的创建和依赖关系的维护交给容器来管理。这样的好处是让代码更加灵活和可扩展。

IoC 的作用是什么?

IoC 的作用是解耦,减少代码之间的耦合,使得代码结构更加清晰,易于维护和扩展。

IoC 的实现方式有哪些?

IoC 的实现方式有两种:控制反转 (IoC) 和依赖注入 (DI) 。

Spring IoC 容器是如何管理 bean 的生命周期的?

Spring IoC 容器管理 bean 的生命周期,从创建到销毁,容器会负责调用 Bean 的生命周期回调方法,例如初始化方法和销毁方法。

Spring 中的 Bean 有哪些作用域?

Spring 中的 Bean 有如下作用域:

  • singleton:单例,默认作用域,在整个应用中只创建一个实例
  • prototype:原型,每次获取 Bean 都会创建一个新的实例
  • request:Web 应用中的请求作用域,每次 HTTP 请求都会创建一个新的实例
  • session:Web 应用中的会话作用域,在同一个会话中共享一个实例
  • global session:全局会话作用域,用于 Portlet 应用。

如何实现自动装配(Autowiring)?

自动装配(Autowiring)可以自动地将依赖注入到某个bean中,从而减少配置的工作量。它可以通过在bean的定义中设置autowire属性来实现,可以设置为"byName",“byType"或"constructor”。

如何使用 Spring 的 BeanFactory 容器?

Spring BeanFactory是Spring框架中最基本的IOC容器,它是实现IOC的最基本方式,通过使用XML文件来配置bean,然后通过BeanFactory接口来获取bean。

如何使用 ApplicationContext 容器?

ApplicationContext是一个扩展自BeanFactory的容器,它包含了除了BeanFactory所提供的功能以外的更多特性,例如支持国际化,事件传播等。

Spring 容器如何完成对象依赖关系的注入?

Spring容器使用依赖注入(DI)来完成对象间的依赖关系。通过在bean的配置文件中定义bean之间的关系,在容器中创建bean时,容器会根据配置文件中的信息来完成依赖关系的注入。

在Spring IOC中,什么是Bean?

Spring 中的 Bean 有单例(Singleton)、原型(Prototype)、会话(Session)、请求(Request)等多种作用域。

Bean之间存在循环依赖怎么办?

可以使用@Lazy注解避免循环依赖。

26.spring bean的生命周期?
  • 实例化 Instantiation
  • 初始化–属性赋值 Populate
  • 初始化–增强实现 PostProcessor
  • 使用和销毁 Destruction
27.spring和springboot的关系是什么?

Spring Boot是Spring框架内的一个模块,它提供了一种简化新Spring应用程序引导和开发的方法。它提供了一系列默认配置和命令行界面,使开发、测试和部署Spring应用程序变得更加容易。

换句话说,Spring Boot是一个用于快速高效地构建生产就绪Spring应用程序的框架。它使用Spring框架作为基础,但它处理了通常需要的大量配置和设置工作,使开发人员可以专注于编写应用程序的业务逻辑。

因此,总之,Spring和Spring Boot的关系是,Spring Boot建立在Spring框架上,并提供了更方便和简化的开发Spring应用程序的方法。

28.springboot用哪些优点?
  1. 快速开发:通过使用 Spring Boot 快速搭建项目,并可以自动配置大部分功能。
  2. 内嵌容器:Spring Boot 内嵌了Tomcat、Jetty等多种 Servlet 容器,以及内嵌数据源,不用再额外安装繁琐的配置过程。
  3. 自动配置:Spring Boot 自动根据项目的依赖自动配置相关功能,比如数据库连接、消息队列等。
  4. 代码生成器:Spring Boot 提供了一系列的生成器,可以帮助快速生成代码,减少代码量。
  5. 简化部署:通过使用Spring Boot,可以使用单独的 jar 包部署,方便简单。
  6. 可插拔性:Spring Boot 可以支持热部署、动态加载,并可以随时切换到其他容器,提高了项目的灵活性。
29.如何自定义一个SpringBootStarter?

自定义 Spring Boot Starter 是一种很方便的封装和发布你自己的 Spring Boot 应用的方式。具体步骤如下:

  1. 创建一个 Maven 项目:创建一个新的 Maven 项目,并在 pom.xml 文件中添加相关的依赖。
  2. 创建配置类:创建一个配置类来读取配置文件,并将配置映射到对象。
  3. 创建自动配置类:创建一个自动配置类,以向 Spring Boot 应用提供配置信息。
  4. 创建自动配置模块:创建一个自动配置模块,以将自动配置类和配置类关联起来。
  5. 发布到 Maven 仓库:将你的自定义 Starter 发布到 Maven 仓库,以便其他开发人员使用。
  6. 使用自定义 Starter:在你的 Spring Boot 应用中使用自定义 Starter。
30.在浏览器输入url,给我们返回结果,这个过程中发生了什么事情?
  1. 浏览器将 URL 解析为主机名和端口号。
  2. 浏览器向域名系统 (DNS) 发送请求,询问 URL 对应的 IP 地址。
  3. DNS 响应请求,返回 IP 地址。
  4. 浏览器向该 IP 发起 HTTP 请求。
  5. 该 IP 的 Web 服务器收到请求,并将请求分发到相应的 Web 应用程序或 Web 页面。
  6. Web 应用程序根据 URL 和请求方法 (如 GET 或 POST) 进行处理,并生成响应内容。
  7. Web 服务器向浏览器发送 HTTP 响应。
  8. 浏览器渲染页面,并显示给用户。

这个过程中使用了多种协议,如 DNS、HTTP 等,同时也涉及到了 Web 服务器、浏览器、DNS 和 Web 应用程序等多个组件。

https://blog.csdn.net/weixin_45296116/article/details/124226905

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ULDueV5x-1676170589437)(C:\Users\momo\AppData\Roaming\Typora\typora-user-images\image-20230129152524638.png)]

img

31.java内存模型、GC、线程安全、线程池

Java内存模型 (JMM) 是 Java 程序并发的基础。JMM 确定了 Java 程序中各线程之间的内存可见性和线程安全的语义。

GC (垃圾回收) 是 Java 程序内存管理的一个关键部分。Java 虚拟机实现了垃圾回收机制,负责回收不再使用的内存空间。

线程安全是指在多线程环境下,一个对象在多线程并发访问和操作时仍然能够保持合法状态,不受其它线程的影响。

线程池是一种通用的线程管理机制,允许应用程序处理多个请求,而不必每次请求都创建一个新线程。线程池中维护了一组线程,应用程序可以重复使用线程池中的线程来处理多个请求。

一些概念

Xms 起始内存

Xmx 最大内存

Xmn 新生代内存

Xss 栈大小。 就是创建线程后,分配给每一个线程的内存大小

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

-XX:MaxPermSize=n:设置持久代大小

收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
Survivor=3:2,一个Survivor区占整个年轻代的1/5

-XX:MaxPermSize=n:设置持久代大小

收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值