Java面试常见的面试题(持续更新版)

一丶基础知识

1.面向对象(工作时间不是很长的出现频率)

什么是面向对象?什么是面向过程?

面向过程:

例子:我要洗衣服    把衣服放进洗衣机→加入洗衣液→关上洗衣机门→按下启动按钮

面向对象:

例子:我要洗衣服   对象有  我    洗衣机

我要做的事:  把衣服放进去   加入洗衣液   关门   按启动按钮

洗衣机要做的事:   清洗

以上可以看出,面向过程比较高效比较直接,面向对象更易于扩展丶维护和复用

封装

明确标识出允许外部使用的所有成员函数和数据项,内部细节对外部调用透明,外部调用无需修改和关心内部是如何实现的,用就可以了

例1:Javabean

属性私有,提供getset对外访问,属性的赋值和获取逻辑只能由Javabean本身决定,不能外部随意修改

例2:orm框架
操作数据库不需要关心是如何建立链接的,SQL是如何执行的,只需要引入mybatis调用方法就行

继承

关键字:extends

子类继承父类的所有属性,只需要扩展自己的个性化

多态

使用条件:继承丶方法重写和父类引用指向子类对象

弊端:无法调用子类特有功能,子类的方法不是重写父类的就不行

2.jdk丶jre丶jvm区别和联系

jdk

提供给开发者使用的工具

jre

运行环境

jvm

虚拟机,解释class文件,一次编译到处运行,包含多版本系统解释

jdk包含jre→jre包含jvm

3.==和equals

==对比的是栈中的值,基本数据类型是存在栈中,引用类型是是堆中对象的地址

equls默认也是使用的==比较,通常会重写

public class StringDemo{
    public static void main{

        String str1 = "hello";//存在堆中的常量池
        String str2 = new String("hello");//存在堆中
        String str3 = str2;
        System.out.println(str1 == str2)://f
        System.out.println(str1 == str3)://f
        System.out.println(str2 == str3)://t
        System.out.println(str1.equals(str2))://t
        System.out.println(str1.equals(str2))://t
        System.out.println(str2.equsla(str3))://t
    }

}

4.ArrayList和LinkedList

ArrayList:基于动态数组、查询快 插入删除慢

连续内存存储,适合下标访问(采用一个元素所占的内存长度*下标位置就可以很快的找到元素所在下标的值)

什么是动态数组?

比如静态数组定义长度10,超过10个就会下标越界

动态数组存储超过定义长度就会新建一个数组自动扩容,把之前数组的内容移入新的数组内,原来的数组就会被回收。

使用尾插法(只在数组尾部插入不在头部和中间插入)和指定初始容量(初始100容量运行是就会现在内存中开辟100个空间,初始容量越大越浪费内存)可以提升性能,甚至超过linkedList

LinkedList:基于链表、查询慢  插入删除快

分散在内存中,根据链表的指针一个一个的找,

需要大量创建node对象,无论放什么元素都会创建一个node对象

遍历LinkedList必须使用iterator不能使用for循环,因为取得某一元素都需要对list重新遍历,性能消耗大

5.String StringBuffer StringBuild

String

使用final修饰,不可改变,每次操作都会生成新的string对象

StringBuffer

在原对象的基础之上操作,方法都是使用synchronized锁修饰的,线程安全

StringBuild

在原对象的基础之上操作,线程不安全

什么是线程安全与不安全?

线程安全就是多线程环境,共享变量,保证值不会变不会被修改

二丶Spring

1.spring的两大核心思想

IOC

控制反转:把对象的管理交给ioc容器去管理(比如创建、属性设置、初始化、销毁)

依赖注入:@Autowired和@Resource,@Autowired注解是spring提供的而@Resource注解是有J2EE提供的,@Autowired注解默认通过bytype而@Resource注解默认通过byName注入,

AOP

面向切面编程是对oop面向对象的一种补充,spring AOP 是利用动态代理机制如果一个bean实现了接口那么就会采用jdk动态代理生成该接口的代理对象,AOP的使用场景包括日志记录,性能统计,安全控制,事务处理,异常处理等等。

2.spring的懒加载和非懒加载有什么区别

懒加载:需要使用对象的时候才创建

非懒加载:也叫迫切加载,容器启动的时候就创建对象

3.bean的四种注册方式及注册Bean的注解

1.普通注册方式,直接通过class注册

2.静态工厂方式

3.实例工厂方式

4.FactoryBean方式

控制层:@controller@RestController

服务层:@Service

持久层:@Repository

一般类:@Component

配置类:@Configuration

4.Bean的生命周期

实例化- -属性注入- -初始化- -使用- -销毁

5.BeanFactoryApplicationContext有什么区别

BeanFactory是ioc容器的核心,包含了bean的最基本的方法如实例化、配置、管理、获取bean的方法

ApplicationContext是BeanFactory的子接口除了继承了bean的所有方法还有环境、国际化、资源、事件等服务相关的接口

6.@Transactional

什么是事务

一组对数据库的操作,把这一组看成一个再给你,要么全部成功,要么全部失败。
事务的四大特性
原子性:指的是一个事务应该是一个最小的无法分割的单元,不允许部分成功部分失败,只能同时成功,或者同时失败
持久性:一旦提交事务,那么数据就应该持久化,保证数据不会丢失
隔离性:两个事务修改同一个数据,必须按顺序执行,并且前一个事务如果未完成,那么中间状态对另 一个事务不可见
一致性:要求任何写到数据库的数据都必须满足预先定义的规则,它基于其他三个特性实现的
InnoDB 如何保证原子性和持久性的
通过 undo log 保证事务的原子性, redo log 保证事务的持久性
undo log 是回滚日志,记录的是回滚需要的信息, redo log 记录的是新数据的备份
当事务开始时,会先保存一个 undo log ,再执行修改,并保存一个 redo log ,最后再提交事务。如果系统崩溃数据保存失败了,可以根据redo log 中的内容,从新恢复到最新状态,如果事务需要回滚,就根 据undo log 回滚到之前的状态
事务隔离级别有哪些,分别能解决什么问题
读未提交:事务读不阻塞其他事务的读和写,事务写阻塞其他事务的写但不阻塞读,能解决第一类丢失更新的问题,
读已提交:事务读不会阻塞其他事务读和写,事务写会阻塞其他事务的读和写,能解决第一类丢失更新,脏读的问题
可重复读:事务读会阻塞其他事务的写但不阻塞读,事务写会阻塞其他事务读和写,能解决第一类丢失更新,脏读,不可重复读,第二类丢失更新问题
串行化:使用表级锁,让事务一个一个的按顺序执行,能解决以上所有并发安全问题

开启事务的条件?

在 Java 中,事务通常用于确保一系列操作在数据库中作为单个单元执行,事务主要应用于数据库操作,并且可以通过使用 Java Database Connectivity (JDBC) API 或 Java 与数据库交互的其他框架(例如 Spring, Hibernate 等)来处理

  1. 数据库支持:首先,数据库必须支持事务处理。一些数据库,如 MySQL 的 MyISAM 存储引擎不支持事务,而 InnoDB 存储引擎则支持。

  2. 使用 ORM 框架:当使用像 Hibernate 或 Spring 这样的 ORM (对象关系映射) 框架时,事务管理可以通过注解或配置来更加简洁地处理。例如,在 Spring 中,可以使用 @Transactional 注解来标记一个方法,表明该方法应该在一个事务中运行。

  3. 隔离级别和传播行为:在复杂的应用程序中,可能需要设置事务的隔离级别和传播行为。这些设置控制并发事务如何交互以及在调用其他事务方法时事务如何传播。

@Transactional注解通常用在service层,因为业务逻辑通常在这一层进行,而事务管理是业务逻辑的一部分。

使用@Transactional什么情况下会导致事务不会回滚?

1.抛出异常throws IOException

2.捕获异常使用try catch

3.数据库不支持事务

等等.....

7.常见Http状态码

200 成功返回状态
301 永久重定向,被请求的资源永久移动到新位置
302 临时重定向,被请求的资源临时移动到新的位置,项目中使用了 oauth2 ,对目标资源访问无权限时
就会见到,它是会重定向到授权地址
401 无权限访问
403 禁止访问,服务器已经接收到请求,但拒绝执行 404 找不到该资源
500 服务器内部错误 zuul 找不到服务名就会见到
503 服务器内部错误 服务器维护或者过载
504 网关超时

8.Servlet的生命周期

1.初始化后调用 init()方法

2.调用service()方法来处理客户端的请求

3.销毁前调用destory()方法

4.servlet由jvm垃圾回收器进行回收

9.Sessioncookie有什么区别

session 是以 ConcurrentHashMap 结构存储在服务器端,同时生成一个 sessionid 返回客户端并存放到 cookie中
cookie 是将数据存储在客户浏览器端
10.get post 请求的区别

get是把参数放在url地址中,长度有限制,一般用于查找

post是吧参数放到request body中,更安全,一般用于添加、修改操作

11.SpringMVC常用的注解有哪些

@Controller :标识一个类是控制器类
@RequestMapping :映射请求路径和参数
@ResponseBody :将返回值放到 responsebody 中,通常返回 json 或者 xml 格式数据
@RequestBody : 将前台请求参数转换成对象
@PathVariable :接收路径参数,通常用在 restful 接口中
@RestController :@Controller和 @ResponseBody 的组合注解
@ControllerAdvice :运用 aop 的思想,对全局做一些处理,比如结合 @ExceptionHandler 做全局异常 捕获

12.拦截器和过滤器的本质

过滤器(Filter):前端访问后台一堆请求过来时,过滤掉一些不合法的请求

拦截器(Interceptor):执行一个方法时,在方法执行前后打印日志

1. 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
2. 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
3. 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

13.@SpringBootApplication注解的含义

@SpringBootApplication是spring boot项目的核心注解目的是开启自动配置,包含三个子标签
@ComponentScan   开启 ioc 自动扫描注解
@EnableAutoConfifiguration   启用 springboot自动配置, 自动所有扫描 classpath 目录下面 所有 jar 中的 spring.factories 文件实现配置类批量注册
@SpringBootConfifiguration   springboot 配置类

14.SpringBoot如何做全局异常处理

可以使用 @ControllerAdvice 注解,编写一个全局异常处理类,再自定义一个方法使用
@ExceptionHandler 来捕获具体的异常并作相应的处理

15.SpringBoot 中如何管理事务

事务(transaction)是指业务逻辑上对数据库进行的一系列持久化操作,要么全部成功,要么全部失败。在主启动类上加上@EnableTransactionManagement开启事务管理器,在具体的实现层service类上加上@Transactional 实现事务

16.SpringBoot启动流程

1. 开启秒表计时
2.starting 监听器,
3. 处理应用参数
4. 加载环境对象
5. 打印横幅
6. 创建 Spring 容器对象: AnnotationConfifigApplicationContext
7. 容器刷新的前置工作
8. 刷新容器 ,这里会执行 spring ioc 属性容器的 refrsh 方法 ,Bean 的加载,初始化等都在这个里面,
Tomcat 的启动也在这个方法里面。
9. 刷新容器后置工作
10. 秒表停止
11.started 事件
12. 调用 runner
13.running.listeners.

17.SpringBoot自动配置原理

在启动类上我们会打上: @SpringBootApplication 注解,它是一个组合标签,包括:
SpringBootConfuration , 本质是一个 Confifiguration ,代表 Spring 的配置类。
IOC 自动扫描的注解 , ComponentScan 会去扫描类上是否有: @Component ,@Respository
,@Service @Controller , 如果有,就会把这个类自动注册到 Spring 容器中。
EnableAutoConfifiguration :就是启动 SpringBoot 自动配置的注解
@EnableAutoConfifiguration 注解中,注册了一个选择器,其中有一个方法会去返回很多的自动配置 的全限定名,这些类会自动注册到Spring 容器中

三丶MyBatis

1.MyBatis${}取值和#{}取值的区别

#{} 能够防止 SQL 注入,因为底层使用 PreparedStatement 对象,预编译,性能较高
${} 不能防止 SQL 注入,因为底层使用 Statement 对象,不会预编译而是拼接字符串,性能较低
如果需要动态传入表名或者字段名需要用 ${} 比如,像 ORDER BY 时只能使 用${}

2.MyBatis关联查询中,延迟加载和饥饿加载的区别

延迟加载,是先从单表查询,需要使用关联数据的时候才发起关联查询,不用的时候不查询关联的数 据,又叫懒加载, 饥饿加载,是在查询时将关联的数据立即查询出来加载进内存,不管用不用

3.MyBatis对象关联查询和集合关联查询怎么做

单个关联对象用 associate ,适用于多对一的关联查询,使用 javaType 来定义实体类型,集合用
collection ,适用于一对多的关联查询,使用 ofType 来定义集合的泛型类型

4.MyBatis一级缓存和二级缓存的区别

缓存,是指将从数据库查询出的数据存放在缓存中,下次使用相同查询时不必再从数据库查询,而是直 接从缓存中读取,从而减轻数据库查询的压力,提高性能
mybaits 中的一级缓存,是 SqlSession 级别,默认开启,使用同一个 SqlSession 发送相同的 SQL 时命 中;它的生命周期和SqlSession 一致,当调用 SqlSession.close() 方法时会释放缓存
mybatis 中的二级缓存,是 namespace 级别,默认不开启,执行同一个 namespace 的相同 statement , 发送相同的SQL 时命中;它的生命周期是程序结束
SQL 中执行了 update() delete() insert() 操作,则缓存中的数据都会清空

5.Mybatismapper如何传递多个参数

方式一,可以使用 map 进行传参, SQL 中使用 map key 来引用取值
方式二,可以在 SQL 中使用 #{param1} #{param2}... 来引用取值,它是根据 mapper 接口对应方法中形参的顺序进行匹配的,不管接口方法的参数名字叫个啥,SQL 都只能使用 param1 param2 ,等来取
方式三,可以使用 @Param 注解,给 mapper 接口方法的参数命名,在 SQL 中直接使用取的名字来引用

6.MyBatis的动态SQL标签有哪些?如何动态修改SQL?

if 标签:条件判断
choose when otherwise 标签:选择结构,类似 java 中的 switch
trim 标签:对包含的内容加上前缀,后缀
where 标签:主要是用来简化 SQL 语句中 where 条件判断的,能智能的处理 and or ,不必担心多余导致语法错误
foreach 标签:遍历元素
使用 Mybatis 的拦截器可以做到动态修改SQL

7.为什么要使用连接池

对数据库的操作都需要取得连接,使用完都需要关闭连接,如果每次操作需要打开关闭连接,这样系统性能很低下。连接池就可以动态的管理这些连接的申请,使用和释放,我们操作数据库只需要在连接池里获取连接,使用完放回连接池,这样大大节省了内存,提高效率。

四、Redis

1.讲一下你理解的Redis

Redis 是一种高性能的,开源的, C 语言编写的非关系型数据库,可以对关系型数据库起到补充作用,同 时支持持久化,可以将数据同步保存到磁盘

2.Redis的数据存储结构有哪些,他们的使用场景分别是什么

Redis 存储形式是键值对,支持 value 形式包括 String List Set ZSet Hash
String 可以用作缓存,计数器,防攻击,验证码、登录过期等, List 可以用来做队列,秒杀等, Set 可以用来去重

3.怎么防止 Redis 宕机数据丢失问题
通过对 Redis 持久化,把内存中的数据和命令,保存一份到磁盘中做备份,当 Redis 发生宕机,重启服务器的时候,会从磁盘重新加载备份的数据,从而解决数据丢失问题

4.Redis持久化是什么?有几种方式

将内存中的数据备份到磁盘的过程,就叫作持久化
Redis 持久化主要有两种方式, RDB AOF ,可以通过修改 redis.conf 进行配置
RDB 是记录数据快照,而 AOF 是记录写命令的

5.Redis用在哪些业务上

主要用做缓存 , 比如:验证码,分类缓存,数据字典缓存,权限数据缓存,登录信息缓存等。
String 类型的存储结构用的比较多,并且使用了 Json 格式进行序列化。

6.淘汰策略有哪些?

volatile-lru :从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
volatile-ttl :从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random :从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru :从数据集中挑选最近最少使用的数据淘汰
allkeys-random :从数据集中任意选择数据淘汰
no-enviction :不使用淘汰

7.Redis事务和Mysql事务的区别

Mysql 的事务是基于日志,记录修改数据前后的状态来实现的,而 Redis 的事务是基于队列实现的
Mysql 中的事务满足原子性:即一组操作要么同时成功,要么同时失败,
Redis 中的事务不满足原子性,即一组操作中某些命令执行失败了,其他操作不会回滚
因此对于比较重要的数据,应该存放在 mysql

8.为什么要使用Redis做缓存

一个字,快。
缓存它指的是将数据库的数据同步到内存中,客户端获取数据直接从内存中获取。由于内存读写速度大于磁盘,而使用缓存能减少磁盘读取,大大提高查询性能。
我们一般会将经常查询的,不会经常改变的热点数据,保存到缓存中,提高响应速度

9.怎么保证RedisMysql的一致性

我们在代码中控制,如果数据库做是写操作,直接把 redis 中的对应数据删除,下次查询数据会重新写入缓存。
我们的业务对一致性要求不是很高,因此采用了先操作 mysql ,后删除 redis 。在写数据库和删除缓存行 代码之间如果有查询请求依然会查询到Redis 中的老数据,但是这种情况非常极端,而且我们的业务也 能容忍这种短暂的脏数据。
我还知道其他方案,比如延迟双删 , 监听 Mysql 事务日志自动同步 Redis 等。

10.缓存击穿,穿透,雪崩怎么处理?
缓存击穿:缓存中没有,数据库中有的数据,由于某种原因比如缓存过期了,同时并发用户特别多,一 时间都往数据库中读取数据
解决方案:加互斥锁,只能允许一个线程访问数据库,然后其他线程就可以往内存中拿
缓存穿透:客户端频繁请求一个缓存和数据库中都没有数据,导致数据库压力大。
解决方案:布隆过滤器来判断数据库中有没有这个 key
缓存雪崩:缓存重启,或者大量 key 失效,导致大量并发打到数据库
解决方案:为 key 设置不同的过期时间

五、RabbitMQ

1.RabbitMQ的使用场景

rabbitMQ 消息队列可以用来
做任务的异步处理,提高程序的相应时间
提高系统稳定性,通过手动确认机制,当消费者出现故障,只要没有确认签收,请求的数据都不会
丢失可以再次处理
服务解耦,生产者通过 MQ 与消费者交互
消除峰值,通过异步处理,消息传到 MQ 直接返回,接着等待排队处理,避免了线路拥堵

2.RabbitMQ如何防止消息丢失

首先, RabbitMQ 的消息确认机制,默认是自动签收,也就是说消息一旦被消费者接收,就自动签收, 消息就从队列里清除了。因此对于重要的消息,不容丢失的数据,我们需要设置在消费完成后手动签收
其次,我们可以将消息持久化,避免消息在消费前 MQ 宕机,网络问题等造成的消息丢失

3.如何防止消息重复消费

重复消费,一般时由于消费者消费成功后,在给 MQ 确认签收的时候出现了网络波动, MQ 没有接到确 认,就会继续给消费者投递之前的消息,造成消费者接收到了两条一样的消息。
我们可以通过实现消息的幂等性来避免这种情况,比如说让生产者给每个消息携带一个唯一的 id ,消费 者获取消息后根据这个id 去查询数据库,如果不存在就正常消费,如果存在了就证明该消息被消费过, 直接丢弃

4.什么是幂等

重复请求结果最终只算一次,保证结果的唯一性

六、微服务

1.什么是集群

集群使将应用复制成多个相同的应用,一起来工作,从而提高工作能力。即将多个应用程序分散在不同 的服务器,每个服务器都独立运行相同的代码。可以分散服务器压力解决高并发的问题,同时也能预防 单节点故障,即一台服务器故障不影响其他服务器正常运行,但没有解决单体应用代码臃肿,业务复 杂,维护性差等等问题

2.什么是负载均衡

使用了集群后,解决高并发同时有一个新的问题,就是客户端的请求如何分配到多台服务。因此需要通 过负载均衡器,比如Nginx ,使用负载均衡算法比如轮询、权重、随机等等将请求路由到不同的服务器

3.集群和分布式的区别

集群是将一个应用程序复制多份,部署在多台服务器上,每个服务器中的程序都是完整的,可以独立运行
分布式是将一个应用程序拆分成多个子程序,分别部署在多台服务器上,每个服务器中的程序都是不完整的,所有服务器需要相互通信相互协调才能完成最终的业务
集群能解决高并发问题,同时能防止单节点故障,即一台服务器宕机不影响其他服务器的正常运行
分布式也能解决高并发问题,但不能防止单节点故障,即一台服务器宕机了,整体业务就无法完成
集群无法解决项目本身的代码臃肿、业务复杂等等问题,分布式能降低模块之间的耦合
实际应用中,我们可以将分布式和集群相结合,比如分布式某个子程序的负载很高,可以单独对这个子 程序做集群

4.SpringCloud有哪些常用组件

Eureka :做服务注册与发现,用来解决服务之间通信问题
Ribbon/OpenFeign :用做客户端的负载均衡,也就是解决将请求路由到微服务集群的问题
Hystrix :断路器,它的熔断、降级策略用来解决单节点故障
Zuul :做服务网关,它是整个微服务的大门,可以用来实现登录、权限检查等业务
Confifig :分布式配置中心,用来统一管理配置所有微服务的配置文件

5.Spring,SpringBootSpringCloud的关系以及区别

Spring 是一个开源的轻量级控制反转和面向切面编程的容器框架。轻量级是说它开发使用简单,功能强 大。控制反转是指将对象的创建,销毁控制交给ioc 容器,方便解耦合,降低维护难度,面向切面编程 是指将相同的逻辑横向抽取出来,可以对一些通用业务如事务,日志进行集中管理。
Springboot 是一个基于 spring 的框架,对 spring 做了大量简化,使开发流程更快,更高效。比如它大量 简化maven 依赖,基于注解配置(JavaConfifig)无需 XML ,内嵌 Tomcat ,部署流程简单,打包和部署 更加灵活,允许独立运行
SpringCloud 是基于 SpringBoot 实现的,用于微服务架构中管理和协调服务的,它是一系列框架的有序 集合,它为开发者提供了一系列工具,例如服务发现与注册,配置中心,网关,负载均衡,熔断器,链路追踪等等,让微服务架构落地变得更简单

七、多线程

1.创建线程是几种方式

方式一:继承 Thread 类,覆写 run 方法,创建实例对象,调用该对象的 start 方法启动线程
方式二:创建 Runnable 接口的实现类,类中覆写 run 方法,再将实例作为此参数传递给 Thread 类有参构造创建线程对象,调用start 方法启动
方式三:创建 Callable 接口的实现类,类中覆写 call 方法,创建实例对象,将其作为参数传递给
FutureTask 类有参构造创建 FutureTask 对象,再将 FutureTask 对象传递给 Thread 类的有参构造创建线程对象,调用start 方法启动

2.Synchronized lock的区别

他们都是用来解决并发编程中的线程安全问题的,不同的是 synchronized是一个关键字,依靠 Jvm 内置语言实现,底层是依靠指令码来实现; Lock 是一个接 口,它基于CAS 乐观锁来实现的
synchronized 在线程发生异常时,会自动释放锁,不会发生异常死锁, Lock 在异常时不会自动释
放锁,我们需要在 fifinally 中释放锁
synchronized 是可重入,不可判断,非公平锁, Lock 是可重入,可判断的,可手动指定公平锁或
者非公平锁

3.观锁和乐观锁

悲观锁认为,对同一个数据的并发操作,一定是会被其他线程同时修改的。所以在每次操作数据的
时候,都会上锁,这样别人就拿不到这个数据。如果不加锁,并发操作一定会出问题。用阳间的话
说,就是总有刁民想害朕
乐观锁认为,对同一个数据的并发操作,是不会有其他线程同时修改的。它不会使用加锁的形式来
操作数据,而是在提交更新数据的时候,判断一下在操作期间有没有其他线程修改了这个数据
悲观锁一般用于并发小,对数据安全要求高的场景 , 乐观锁一般用于高并发,多读少写的场景,通常使用版本号控制,或者时间戳来解决.

4.什么是线程安全?什么是不安全?如何保证线程安全?

线程安全(Thread Safety)是指程序的一个特性,它在多线程环境下能够正常并且可预测地运行。当多个线程访问共享数据或资源时,如果这个过程无需额外的同步或协调,并且结果符合预期,那么可以称之为线程安全。

线程不安全,正是与线程安全相对的概念。当多个线程访问共享资源时,如果不采取适当的同步机制,可能会导致数据的不一致性或其它不可预测的结果。这通常是由于线程间的竞态条件(race conditions)引起的,即多个线程同时修改共享数据,导致数据状态不可预测。

使用synchronized关键字

使用volatile关键字

使用锁:ReentrantLock。使用这些锁,你可以实现更复杂的锁策略。

5.线程池的作用

请求并发高的时候,如果没有线程池会出现线程频繁创建和销毁而浪费性能的情况,同时没办法控制请 求数量,所以使用了线程池后有如下好处
主要作用是控制并发数量,线程池的队列可以缓冲请求
线程池可以实现线程的复用效果
使用线程池能管理线程的生命周期

6.线程池的执行流程

核心线程 => 等待队列 => 非核心线程 => 拒绝策略

7.线程池拒绝策略有几种

拒绝策略,当线程池任务超过 最大线程数 + 队列排队数 ,多出来的任务该如何处理取决于 Handler
1. AbortPolicy 丢弃任务并抛出 RejectedExecutionException 异常;
2. DiscardPolicy 丢弃任务,但是不抛出异常;
3. DiscardOldestPolicy 丢弃队列最前面的任务,然后重新尝试执行任务;
4. CallerRunsPolicy 由调用线程处理该任务
可以定义和使用其他种类的 RejectedExecutionHandler 类来定义拒绝策略。

八、MySQL

1.什么是索引
索引是用来高效获取数据的存储结构如同字典的目录一样,数据库的索引通常使用 b+tree 来实现,索引树的节点和数据地址相关联,查询的时候在索引树种进行高效搜索,然后根据数据地址获取数据。索引提高了搜索的效率同时增加了索引维护的成本,滥用索引也会降低insert,update,delete 的性能。

2.Mysql索引有哪些类型

普通索引:允许重复的值
唯一索引:不允许有重复的值
主键索引:数据库自动为我们的主键创建索引,如果我们没有指定主键,它会根据没有 null 的唯一索引 创建主键索引,否则会默认根据一个隐藏的rowId 作为主键索引
全文索引:用来对文本域进行索引,比如 text varchar ,只针对 MyISAM 有效

3.索引方式有哪些

B+ 树和 hash Myisam innodb 都不支持 hash

4.InnoDB的索引结构和MyIsam的索引结构有什么区别

他们都是用的 B+ 树,不同的是
innodb 的叶子节点存放的是数据, myisam 的叶子节点存放的是数据的地址
innodb 中辅助索引的叶子节点存放的是主键索引的键值, myisam 中辅助索引的叶子节点存放的也
是数据的地址
innodb 的索引和数据都存放到一个文件中, myisam 的索引和数据分别存放到不同的文件中

5.哪些因素会造成索引失效

模糊查询时,通配符放到左边的时候,会导致索引失效 比如 like ''%keyword%''
列是字符串类型,查询条件没有用引号,会导致索引失效
使用了 or in not in not exist != 等,会导致索引失效
查询 null 值,会导致索引失效
还有 mySQL 认为全表扫描会比索引查找快,就不会使用索引,比如表里只有一条记录

6.优化SQL

不需要的字段就不要查询出来
小结果集驱动大结果集,将能过率更多数据的条件写到前面
in not in 尽量不要用,会导致索引失效
避免在 where 中使用 or 链接条件,这会导致索引失效
给经常要查询的字段建立索引
考虑如果不需要事务,并且主要查询的化,可以考虑使用 MyISAM 存储引擎
如果表数据量实在太庞大了,考虑分表

7.哪些因素可能会造成数据库性能问题

不合理的商业需求,比如实时更新总注册人数,总交易额等等,应该考虑不要实时
对于热点数据的查询并发太高,应该考虑用缓存
数据库结构设计不合理,比如几十个字段集中在一张表,应该考虑分表
SQL 语句有问题,比如太多 JOIN ,很多不需要的字段也要全部查询出来,应该考虑优化 SQL
硬件和网络方面的影响

8.mysql存储引擎有哪些,有什么区别,如何选择

主要有 innodb memory myisam
innodb 支持事务,速度相对较慢,支持外键,不支持全文索引
myisam 速度相对较快,支持全文索引,不支持外键,不支持事务,
memory 不支持事务,基于内存读写,速度快,支持全文索引
如果对事务要求不高,而且是查询为主,考虑用 myisam
如果对事务要求高,保存的都是重要的数据,建议使用 innodb ,它也是默认的存储引擎
如果数据频繁变化的,不需要持久化,可以使用 memory

九、设计模式

1.常见的设计模式说一下
单例模式:一个类只能有一个实例,分为饿汉模式(迫切加载)和懒汉模式(延迟加载)和枚举。
工厂模式:隐藏了产品的复杂创建过程,实现生产功能的复用,让产品生产更加高效。分为简单工厂(需要来回切换生产线),工厂方法(开设新的生产线),抽象工厂(制定创建产品的接口,让子工厂 选择创建哪种产品)
Spring 中各种的 BeanFactory 创建 bean 都用到了
模板模式:定义一个算法骨架或者算法的流程,而不同的实例实现方式不同,将某个或多个具体的实现 延迟到子类中,比如RedisTemplate 实现了 RedisOperations ElasticSearchTemplate 实现了
ElasticsearchOperations
代理模式:不直接使用实际对象,通过调用代理对象间接调用实际对象,主要用作对实际对象的增强, 分为静态代理,JDK 动态代理, CGLIB 动态代理比如 Spring AOP 原理就是动态代理,当目标对象实现 了接口会使用JDK 动态代理,没有实现接口会使用 CGLIB 动态代理
适配器模式:将不兼容的接口转换为可兼容的接口的中间类,比如 HandlerInterceptorAdapter ,我们 定义拦截器时不需要覆写HandlerInterceptor 中的所有方法,因为适配器类帮我们做了空实现。但 JDK1.8之后,给接口中增加了默认方法,可以有方法体,因此这些适配器类已经失去作用了
观察者模式:当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,比如
Spring 中的 ApplicationListener

十、杂乱

1.录实现方案

当用户第一次发起登录请求,后台生成一个 token 保存到 Redis
将生成的 token 返回给用户端
用户端使用用浏览器中的 localStorage 保存 token
通过 axios 的拦截器,给每次请求的请求头都加上 token
服务端收到 token ,就能在 Redis 中找到对应的数据

2.讲讲Git相对于SVN的区别

第一, Git 是每个攻城狮都有自己的版本库,可以在自己的库上任意操作提交代码
第二, Git 在每个工程只产生一个 .git 目录,而 SVN 会在每个目录下都生成 .svn 目录
第三, Git 能快速切换分支,且合并文件的速度比 SVN
第四, Git 采用分布式版本库,内容完整性更好

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值