Java面试题

Java面试宝典

  • 基础篇
  • 进阶篇
    • 在这里插入图片描述
  • 扩展篇
        • Redis (待补充)
        • RocketMQ(待补充)
        • RabbitMQ(待补充)
        • Docker(待补充)
        • Mongodb(待补充)
        • Seata(待补充)
        • Canal(待补充)

基础篇

待补充
先来简单的面试八股文

1、方法重载 和 重写 的区别
重载: 指的是一个类下方法不满足当前使用, 同一个方法名 但是 传递的参数或者返回的参数结果不同 的方法

	public void t1(){} 
	public String t1(){}
	public void t1(String name){}

重写: 特指 子类继承父类,父类方法不满足子类使用,需要对其重新实现 结合模板设计模式理解


2、Java面向对象的三大特性
封装:简单理解就是对 属性进行权限控制,不允许外部直接使用
- private : 私有,仅仅当前类可使用
- protected : 当前类、同包、子类可使用
- public : 公共的、无限制
继承:指的是 子类继承父类、类是单继承、接口是多继承
多态:指的是 Map map = new HashMap(); 编译类型是Map对象,但是实际运行对象是HashMap。多态的实现方式体现在重写、接口、抽象类和抽象方法。


3、String 为什么是不可变的?
首先 String 字符串 意思就是 字符拼接起来的 一个对象,其底层还是一个个char数组,并且是使用了 private 和 final 修饰 :private保证了其对象的内容不会被修改,而final保证了其本身的vale引用地址不会被修改,从而保证了String不会被修改,并且在String中没有set方法保证不会被修改。

			String name1 = "小明";   String name2 = "小明";  name1 = "小红";
			分析: 其实是在常量池创建了 "小明" 这个变量,而 name1 只是将地址指向了 “小明” ,假设将字符可变,
			那引用到他的 name2 的对象也会受到影响。  name1 = “小红”; 只是将	对象 name1 的引用地址变成了 “小红”不是说Striing可变

看了很多解释,唯独这个视频讲解的很透( •̀ ω •́ )✧ --> String不可变视频讲解
Java面试题_第1张图片


4、String、StringBuffer 和 StringBuilder 的区别是什么?
String: 是一个不可变的字符串,底层是由char[]实现,字符串存放在常量池当中,直到对象被销毁。因为String有不可变性,所以引申出了StringBuffer和StringBuilder。
StringBuffer:线程安全的可变字符串对象,性能相对会高,常用的方法有append(),


5、自动装箱与拆箱?

6、接口和抽象类的区别是什么?

7、== 与 equals区别?

8、你重写过 hashcode 和 equals 么,为什么重写 equals 时必须重写 hashCode 方法?

9、线程有哪些基本状态,并描述每种状态?

10、final 关键字修饰这三个地方:变量、方法、类,会有什么作用?

11、说说 &和&&的区别、| 和 | | 区别?

12、ArrayList的拓容机制 、ArrayList和Vector、LinkedList的区别
ArrayList 的扩容机制: 位运算左移一位 、 乘2 ,变成原来的两倍
add方法 首先会先判断是否需要扩容 : ensureCapacityInternal(集合大小)
Java面试题_第2张图片
先看calculateCapacity() 方法
在这里插入图片描述
个人理解就是先判断元素集合是否为空,为空的话返回默认容量10,反之直接返回当前容量。当容量为12 添加到 第13个元素的时候开始扩容
Java面试题_第3张图片
再来看 ensureExplicitCapacity()方法
在这里插入图片描述
定义容量为 12 的数组,当添加到第13个元素的时候开始扩容
Java面试题_第4张图片
Java面试题_第5张图片
ArrayList和Vector、LinkedList区别:
ArrayList 和 Vector 本质上就是数组:
数组有序号,且可以通过序号查询到对应的元素,对应查询效率大大增加,但是对应指定位置的增删慢,因为每一次的增删会导致元素的位置发生变化,每次的增删都需要维护一次数据。扩容慢。
Java面试题_第6张图片

LikedList是链表:
链表主要是由node节点组成,每一个node的指针指向下一元素的内容地址,通过头指针元素一个个查询到对应的元素,无序号,查找效率底,每次都只能从开头开始找,但是随机增删对的效率高,因为不需要维护对应的关系,只需要改变指针指向的元素地址即可删除对应元素,而弃之的node节点将由垃圾回收机制回收
Java面试题_第7张图片


13、描述深拷贝和浅拷贝?

14、HashMap和Hashtable的区别?

15、说说List,Set,Map三者的区别?

16、什么是线程死锁?线程的状态有哪些?

17、Object常用的方法?

18、谈一下HashMap的底层原理是什么?

19、谈一下hashMap中什么时候需要进行扩容,扩容resize()又是如何实现的?

20、浅谈volatile关键字的作用?

  1. 保持内存可见性: 所有线程都能看到共享内存的最新状态。
  2. 防止指令重排

21、什么是API?
API 就是提供对外的一种调用方法
比如:
​ 我们想调用alibaba的durid数据库连接池,就可以导入它的jar包从而使用他的API SDK
​ 另一种则是作为功能服务暴露公共的API接口给外部使用 WEB 请求路径


22、平时在使用HashMap时一般使用什么类型的元素作为Key?

23、什么是Git?
版本控制工具,代码的团队开发、帮助我们备份、代码还原、追溯代码和权限控制
Java面试题_第8张图片


24、Git常见的命令?
git add(提交到暂存区)
git commit(提交到版本库)
git push(提交到远程仓库)
git clone(第一次将整个项目克隆)
git pull(之后得拉取项目)
git status(查看文件状态)
git diff(查看文件的修改)
git reset --hard HEAD^(回到上一个版本)
git reset --hard < commit id > (回到指定版本)
git log (查看日志)

命令 git checkout -- readme.txt 意思就是,把 readme.txt 文件在工作区的修改全部撤销,这里有两种情况:
一:readme.txt 自修改后还没有被放到暂存区(git add),现在,撤销修改就回到和版本库一模一样的状态;
二:readme.txt 已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

注意区分:git checkout filename (切换分支) 和 git checkout – filename (撤销)

删除 : git rm test.txt

查看分支:git branch

创建分支:git branch < name >

切换分支:git checkout < name >

创建 + 切换分支:git checkout -b < name >

将某分支合并到当前分支:git merge < name >

删除分支:git branch -d < name >
Java面试题_第9张图片


25、什么是RestFul风格
Restful 的 四要素: 请求方式、请求方法、请求参数、方法返回值
Restful 是 一种API 的设计规范,按照它的设计规范去编写API 会使我们的代码变得统一,如查询统一使用GET方式、新增统一使用POST、修改统一使用PUT、删除统一使用DELETE,简洁可读性强
@PathVariable 实现路径传参
网页请求路径默认是GET


26、浅谈前后端分离技术
前后端分离就是 前端干前端的事情,后端干后端的事情 达到责任分离的目的,前后只需要专注于前端代码 不需要注重后端业务实现,后端只需要专注于后端代码 不需要注重前端的代码。

优点:责任分离,降低前后端严重耦合

缺点:跨域问题


27、列举常见的HTTP的状态码
200 / 201: 响应成功
400: 参数接收有问题
403: 权限不够访问该页面
404: 找不到访问路径
500: 后端代码有问题
502/503 / 504:网关或者路由有些问题


28、JDK1.8新特性 (待补充)

  1. Lambda表达式
  2. 函数式接口
  3. 方法引用和构造器调用
  4. Stream API
  5. 接口中的默认方法和静态方法
  6. 新时间日期API

29、了解哪些设计模式?用到了哪些?手写一个单例模式
单例模式:
– 懒汉式
– 饿汉式
– 双重锁检测机制
工厂模式:
– 简单工厂模式
– 抽象工厂模式
设计模式


30、get和post请求的区别?
GET 请求只能 URL 编码,而 POST 支持多种编码方式

GET 请求只接受 ASCII 字符的参数,而 POST 则没有限制

GET 请求的参数通过 URL 传送,而 POST 放在 Request Body 中

GET 相对于 POST 更不安全,因为参数直接暴露在 URL 中

GET 请求会被浏览器主动缓存,而 POST 不会(除非自己手动设置)

GET 请求在 URL 传参有长度限制,而 POST 则没有限制

GET 产生的 URL 地址可以被收藏,而 POST 不可以

GET 请求的参数会被完整的保留在浏览器的历史记录里,而 POST 的参数则不会

GET 在浏览器回退时是无害的,而 POST 会再次提交请求


31、转发(Forward)和重定向(Redirect)的区别?

转发是服务器行为,重定向是客户端行为。

  1. 从地址栏显示来说
    forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址. redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
  2. 从数据共享来说
    forward:转发页面和转发到的页面可以共享request里面的数据. redirect:不能共享数据.
  3. 从运用地方来说
    forward:一般用于用户登陆的时候,根据角色转发到相应的模块. redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等
  4. 从效率来说
    forward:高. redirect:低.

32、Cookie和Session的的区别?

  1. session 在服务器端,cookie 在客户端(浏览器)
  2. session 默认被存在在服务器的一个文件里(不是内存)
  3. session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)
  4. session 可以放在 文件、数据库、或内存中都可以。
  5. 用户验证这种场合一般会用 session

33、 说说preparedStatement和Statement的区别?

  1. 效率:预编译会话比普通会话对象,数据库系统不会对相同的sql语句不会再次编译
  2. 安全性:可以有效的避免sql注入攻击!sql注入攻击就是从客户端输入一些非法的特殊字符,而使服务器端在构造sql语句的时候仍然能够正确构造,从而收集程序和服务器的信息和数据。

34、数据库连接池的原理?为什么要使用连接池?
简单理解: 提前创建好指定数量的连接、需要就去“池”中获取,用完再放回去,减少了每次需要都取创建删除的繁琐流程。(提高效率)

  1. 数据库连接是一件费时的操作,连接池可以使多个操作共享一个连接。
  2. 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量、使用情况,为系统开发,测试及性能调整提供依据。
  3. 使用连接池是为了提高对数据库连接资源的管理

多说一句: 线程的连接池也是如此


35、 什么是事务?MySQL的隔离界别有哪些?Spring的事务有哪些?
简单理解: 要么都成功要么都失败,分为 BEGIN(开启事务)、SAVEPOINT (保留点)、COMMIT (提交执行)、ROLLBACK (回滚事务/回到上一个保存点),开启事务之后是一种预处理的状态,修改的数据并没有真正的生效,需要提交后才会成功,这里又引申出了一个问题,那就是开启多个事务都同时修改一条数据需要怎么处理,引申出MySQL的隔离界别。
事务:就是被绑定在一起作为一个逻辑工作单元的 SQL 语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务,准寻ACID原则。

MySQL的隔离界别

  1. 读未提交 (read uncommitted )
  2. 读已提交 (read committed )
  3. 可重复读 (repeatable read )
  4. 序列化/串行化 (serializable )

Spring的事务:

required (默认事务): 如果当前存在了事务,那就融入这个事务中,没有则重新创建

假设出现异常那么update() 和 delete() 方法都会执行失败,因为在同一个事务中。

requires_new : 需要一个新事物,不管外部有没有,如果原来有,就挂起原事务

可以用在记录日志, 银行取钱,中间调用一个 log(); 记录日志方法,
不管取钱是失败还是成功都记录一次

nested : 如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务

(嵌套事务,子事务回滚不影响外层事务,但是外层事务回滚子事务会一起回滚)
PROPAGATION_REQUEIRES_NEW:肯定会创建子事务,父子互不影响;
PROPAGATION_NESTED:肯定会创建子事务,父影响子,子不影响父;
PROPAGATION_REQUEIRED:子事务和父事务合并成一个事务,父子互相影响;

supports : 如果没有就以非事务的方式执行,如果有则融入该事务

never : 只要有事务我就报错

not_supported : 没有就非事务执行,有就直接挂起,然后非事务执行

mandatory : 如果没有,就抛出异常,如果有,就是用当前的


35、导致 spring 事务失效 原因?

  1. 数据库引擎不支持事务
    这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。
  2. 没有被 Spring 管理
  3. 方法不是 public 的
    大概意思就是 @Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式。
  4. 自身调用问题
    this.方法名() / 方法名()
  5. 数据源没有配置事务管理器
  6. 异常被吃了
    自己 try catch
  7. 异常类型错误
    在异常处理 try catch 后 又 throw 出去
    Spring事务失效的 8 大原因,这次可以吊打面试官了! - Java技术栈 - 博客园 (cnblogs.com)

36、在MyBatis中, #{} 和 ${} 的区别是什么?

#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性


37、 查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序?
查询中用到的关键词主要包含六个,并且他们的顺序依次为 select–from–where–group by–having–order by


38、什么是Springle?Spring的核心? (待补充)
IOC :
AOP :
DI


39、Spring 的 AOP中有哪些不同的通知类型? 是怎么是实现的?
通知(advice)是你在你的程序中想要应用在其他模块中的横切关注点的实现。Advice主要有以下5种类型:

  1. 前置通知(Before Advice): 在连接点之前执行的Advice,不过除非它抛出异常,否则没有能力中断执行流。使用 @Before 注解使用这个Advice。
  2. 返回之后通知(After Retuning Advice): 在连接点正常结束之后执行的Advice。例如,如果一个方法没有抛出异常正常返回。通过 @AfterReturning 关注使用它。
  3. 抛出(异常)后执行通知(After Throwing Advice): 如果一个方法通过抛出异常来退出的话,这个Advice就会被执行。通用 @AfterThrowing 注解来使用。
  4. 后置通知(After Advice): 无论连接点是通过什么方式退出的(正常返回或者抛出异常)都会执行在结束后执行这些Advice。通过 @After 注解使用。
  5. 围绕通知(Around Advice): 围绕连接点执行的Advice,就你一个方法调用。这是最强大的Advice。通过 @Around 注解使用。

40、Spring AOP 默认使用jdk动态代理还是cglib?
要看条件,如果实现了接口的类,是使用jdk。如果没实现接口,就使用cglib


41、SpringAOP的应用场景 ?
场景一: 记录日志
场景二: 监控方法运行时间 (监控性能)
场景三: 权限控制
场景四: 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
场景五: 事务管理 (调用方法前开启事务, 调用方法后提交关闭事务 )


42、Spring 的 bean 的作用域?
singleton:在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。
prototype:每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。
request:每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。
session:同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。
application:限定一个Bean的作用域为ServletContext的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。
bean的作用域


43、SpringMVC常用注解?
@EnableWebMvc 在配置类中开启Web MVC的配置支持,如一些ViewResolver或者MessageConverter等,若无此句,重写WebMvcConfigurerAdapter方法(用于对SpringMVC的配置)。
@Controller 声明该类为SpringMVC中的Controller
@RequestMapping 用于映射Web请求,包括访问路径和参数(类或方法上)
@ResponseBody 支持将返回值放在response内,而不是一个页面,通常用户返回json数据(返回值旁或方法上)
@RequestBody 允许request的参数在request体中,而不是在直接连接在地址后面。(放在参数前)
@PathVariable 用于接收路径参数,比如@RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。
@RestController 该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。
@ControllerAdvice 通过该注解,我们可以将对于控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,
这对所有注解了 @RequestMapping的控制器内的方法有效。
@ExceptionHandler 用于全局处理控制器里的异常
@InitBinder 用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中。
@ModelAttribute 本来的作用是绑定键值对到Model里,在@ControllerAdvice中是让全局的@RequestMapping都能获得在此处设置的键值对。


44、 SpringMVC的流程?
(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。


45、如何解决POST请求中文乱码问题,GET的又如何处理呢?
(1)解决post请求乱码问题:

在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;

(2)get请求中文参数出现乱码解决方法有两个:

①修改tomcat配置文件添加编码与工程编码一致

②另外一种方法对参数进行重新编码:

String userName = new String(request.getParamter(“userName”).getBytes(“ISO8859-1”),“utf-8”)

ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。


46、Spring框架中用到了哪些设计模式?
1.工厂设计模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。

2.代理设计模式:Spring AOP功能的实现。

3.单例设计模式:Spring中的bean默认都是单例的。

4.模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式。

5.包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。

6.观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。

7.适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。


47、

30、手写冒泡排序、选择排序、插入排序,说什么是希尔排序、归并排序?哪些排序是稳定的?

31、什么是时间复杂度?

32、Mybatis 和 Mybatis-Plus 区别?

进阶篇

1、现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?

   			    t1.start();
   			    t1.join();	// 等到 t1执行完后才会调用t2.start()
   			    t2.start();
   			    t2.join(); // 等到 t2执行完后才会调用t3.start()
   			    t3.start();
   			    t3.join();  
   	// join(10)表示main线程会等待t1线程10毫秒,10毫秒过去后

2、HashMap初始容量为什么是16?为什么必须是2的幂?如果输入值不是2的幂比如10会怎么样?为什么不直接将key作为哈希值而是与高16位做异或运算?

 	HashMap 默认容量是右位运算4位为16,必须是2的幂次是因为在计算 hash 值的时候能够均匀的分布到数组上,防止hash冲突
 	不直接将key直接作为hash值是防止防止hash冲突激烈,对运算的key在做一次运算

在这里插入图片描述

3、 什么是JUC?
JUC指的是在 java.util.concurrent 包(JUC)中,有各式各样的并发控制工具,这里我们简单介绍几个常用的工具及其使用方式。


4、第一点什么是线程?什么是进程?
一个进程可以有多个线程,每个线程之间可以共享资源,线程是CUP最小的调度单位。


5、并发、并行?
并发:多线程操作同一个资源、本质:充分利用CUP的资源

​ - CUP 一核,模拟出多个线程,天下武功唯快不破,快速交替

并行:多个人一起行走、

​ - CUP 多核,多个线程同时执行,线程池


6、wait/sleep区别?

  1. 来自的类
    wait—>Object ,会释放锁 ,等待,需要被唤醒
    sleep—>Thread ,不会释放锁 ,睡觉,不需要被唤醒
  2. 使用范围!
    wait 必须在同步代码块中执行, 在那里睡着就在哪里醒来
    sleep 可以在任何地方睡
  3. 是否需要捕获异常
    wait 不需要捕获异常
    sleep 需要捕获异常

7、线程的创建方式有哪几种?

  1. 继承 Thread 类
  2. 实现 Runnable 接口
  3. 通过 ExecutorService 和 Callable\ 实现有返回值的线程
  4. 基于线程池的execute(),创建临时线程

8、ReadWriteLock 了解吗?
读的时候可以有多个线程去读,写的时候只能有一个线程去写


在了解什么是读写锁先了解
乐观锁:锁版本
悲观锁:锁对象
表锁:锁整个表,不会出现死锁
行锁:只锁一行,会出现死锁现象
读锁:共享锁,多人可以读,会发生死锁
写锁:独占锁,只能一个人写,会发生死锁
读写锁是一个更加细粒度的锁
Java面试题_第10张图片


9、谈谈线程池?线程池有哪些参数?有哪些拒绝策略?线程池的execute和submit区别?
本质就是优化系统的使用、不用频繁的创建的销毁,线程的复用
优势:降低资源的消耗、提高效率,方便管理,控制最大并发数
已存在的线程池
Java面试题_第11张图片
自定义线程

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor();

Java面试题_第12张图片7大参数
核心线程(正在使用中的),
最大可以支持(最大线程数),
设置时长(60)
设置时长单位(是秒、分、毫秒),//到这里如果超过了时间,发现你并没有没使用,会把核心以外的线程删除
阻塞队列(用来存放多余的不能执行的队列,很多队列是Integer.MAX,无界队列),
线程工厂(用什么样的工厂去产生,产生一个什么样的一个线程)
拒绝测略(如果,核心线程,非核心线程以及队列都满了,那么就会拒绝,需要自己定义)
Java面试题_第13张图片
线程池的拒绝策略

  1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
    这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。
  2. ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。
    使用此策略,可能会使我们无法发现系统的异常状态。建议是一些无关紧要的业务采用此策略。例如,本人的博客网站统计阅读量就是采用的这种拒绝策略。
  3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。
    此拒绝策略,是一种喜新厌旧的拒绝策略。是否要采用此种拒绝策略,还得根据实际业务是否允许丢弃老任务来认真衡量。
  4. ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务。
    如果任务被拒绝了,则由调用线程(提交任务的线程)直接执行此任务。

线程池的execute和submit区别:(待补充)

  1. execute只能提交Runnable类型的任务,无返回值。submit既可以提交Runnable类型的任务,也可以提交Callable类型的任务,会有一个类型为Future的返回值,但当任务类型为Runnable时,返回值为null。
  2. execute在执行任务时,如果遇到异常会直接抛出,而submit不会直接抛出,只有在使用Future的get方法获取返回值时,才会抛出异常。

10、CAS: 是什么 ?AQS:是什么?
CAS:
指的是 Compare and Swap , 它体现的是一种乐观锁的思想,无锁高并发的实现, 比如多个线程要对一个共享的整型变量执行 + 1 操作:

// 需要 不断的尝试获取 
while(true){
    int 旧值 = 共享变量 ; // 比如拿到了当前值 0 
    int 结果 = 旧值 + 1 ; // 在旧值 0 的基础上增加 1 ,正确结果是 1
    /*
    	在这时候如果 别的线程把共享变量改成了 5 ,本线程的正确结果 1 就作废了,这时候
    	compareAndSwap 返回false,重试 直到 返回 true 表示我本线程 做修改 的同时,别的
    	线程没有干扰
    */
    if( compareAndSwap(旧值,结果) ){
        //成功, 退出循环
    }
}

获取共享变量时,为了保证改变了的可见性,需要使用 volatile 修饰。结合 CAS 和 volatile 可以实现无锁并发,适用于竞争不激烈、多核 CPU 的场景下

  • 因为没有使用 synchronized , 所以线程不会陷入阻塞(意味着需要上下文的切换,保存上一次操作的状态),这是 效率 提高的原因之一
  • 但是如果竞争激烈,可以想到重必然频繁发生,反而效率会受到影响

CAS 底层依赖于一个 Unsafe 类来直接调用操作系统底层的 CAS 指令。
Java面试题_第14张图片
AQS:(待补充)
AQS指的是AbstractQuenedSynchronizer抽象的队列式同步器。是除了java自带的synchronized关键字之外的锁机制。
AQS采用的优先队列来解决并发问题,FIFO(First In First Out)先入先出思想。
Java面试题_第15张图片


10、mysql 的 性能优化问题 ?

  1. 硬盘和操作系统的层面优化、 也就是 硬件设施上的提高
    影响mysql的性能因素主要是 cpu、 磁盘的读取速度、可用内存大小 、网络的带框,这一般都会交给我们的 DBA(数据库管理员) 或者 运维管理人员完成,重点关注服务本身所承载的体量,然后再提出合理的指标要求,避免出现资源浪费的情况

  2. 架构设计层面的优化
    mysql 是一个 磁盘访问非常频繁 的关系型数据库 ,在高并发 和 高性能的场景中 ,mysql数据库必然会承受巨大的并发压力,此时优化的方式 可以分为一下几个部分
    (1)搭建mysql的主从集群:单个mysql容易发生单点故障,一旦服务宕机将会导致依赖mysql数据库的服务全部无法响应,主从集群 或者 主主集群 都可以保存服务的高可用
    (2)读写分离设计,在读多 写少的情况下,通过读写分离的方案可以避免读写的冲突,去避免读写冲突
    (3)引入分库分表的机制通过分库可以降低单个服务节省的一个IO压力。通过分表的方式可以降低单表数据量从而去提升sql的查询效率
    (4)针对热点数据可以引入更为高校的分布数据库比如redis,mongoDB等等,可以很好的缓解MySQL的访问压力,还能替身数据的检索性能

  3. mysql程序配置的优化
    一般可以通过my.cnf来完成

    • 比如:mysql 5.7 默认的最大连接数是151个,这个值可以在my.cnf去修改
    • binlog 日志默认是不开启的,我们也可以在这个文件中去修改开启
    • 缓存池 Bufferpool 默认大小配置等等 ,这个配置一般是和用户的安装环境以及用户的使用场景有关,所以官方只会提供一个默认的配置,具体情况具体分析
    • 关于配置项 需要关注两个层面
      • 第一个是配置的作用域: 分为 会话级别 和 全局范围
      • 第二个是否支持热加载:
      • 针对这两个点,需要注意,全局参数的设定对于已经存在的会话是不生效的,会话参数的设定,随着会话的销毁而失效
  4. sql语句执行的优化:

    • 慢sql 的定位和排查,可以通过慢 查询的日志 和 慢查询日志工具分析 ,得到有问题的 sql 列表
    • 第二个是执行计划分析:针对 慢 sql 可以使用 关键字 explain 来去查看当前sql 的执行计划可以重点关注 type、key、rows、filterd等字段从而定位sql执行慢的原因 再去有的放矢的进行优化
    • 使用show profile工具、这个工具是由mysql提供的可以用来分析当前会话中sql语句资源消耗情况的工具,可以用于sql调优的测量,在当前会话中默认情况下show profile 的关闭的状态打开之后会默认保存最近15次的运行结果,针对运行结果慢的sql通过profile 工具进行详细分析可以得到sql执行过程中所有资源的开销情况,比如说 IO 开销、CPU开销、 内存开销等等

sql 的查询一定要基于索引来进行数据扫描

避免索引失效的问题

使用索引扫描,联合索引中的列 ,从左往右,命中越多越好

尽可能使用sql语句用到的索引完成排序

查询语句使用 列信息 代替 * 查询

永远用小结果集驱动大的结果集


11、MySQL的索引?索引失效问题?使用索引的原因?索引的底层原理?SQL优化?
MySQL的索引
普通索引(INDEX)、唯一索引(UNION)、主键索引(ID)、组合索引、全局索引(MyISAM 里)

索引失效问题
索引失效的7种情况 - liehen2046 - 博客园 (cnblogs.com

使用索引的原因

  • 官方定义: 一种帮助mysql提高查询效率的数据结构
  • 索引的优点:
    1、大大加快数据查询速度
  • 索引的缺点:
    1、维护索引需要耗费数据库资源
    2、索引需要占用磁盘空间
    3、当对表的数据进行增删改的时候,因为要维护索引,速度会受到影响

索引的底层原理: (待补充)
B+Tree
Java面试题_第16张图片
SQL优化
sql优化主要是通过对慢sql进行 EXPLAIN 分析,对其可能用到的索引和实际走上的索引进行分析、对扫描行数进行分析
对于工作中有可能是再后续功能迭代的时候对sql进行了修改导致没有走上最优的索引,又或者是sql再添加条件时候组合索引没有覆盖到条件
又或者随着数据量的增加,已经修改sql无法提高查询的效率,只能采用相关的mysql优化问题


12、MySQL的存储引擎?存储原理?
MySQL存储引擎精讲


13、什么是聚簇索引和非聚簇索引?(待补充)
主键索引就是聚簇索引、只需要一次回表查询


14、什么是行锁?表锁?间隙锁?什么情况下行锁会升级为表锁?
行锁
行锁是innodb存储引擎特有的细粒度锁,能够减少锁冲突问题
表锁
表锁指的是对整张表锁住了
间隙锁
间隙锁指的是对 区间行 锁住了,导致无法对这区间内的数据进行操作
什么情况下行锁会升级为表锁:(待补充)

  1. 行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了。
  2. 索引失效

15、高并发?
高并发

首先 什么是高并发?
	高并发意味着大流量,需要运用技术手段来抵抗流量的冲击,这些手段就好比操纵流量,让流量能更平稳地被系统所处理,带给用户更好的体验。
	常见的高并发有,双11、春运抢票、微博热点数据等等,除了这些典型的事情,每秒几十万的秒杀系统,每天千万级的定单系统等等也可以归并为高并发。不能只是但从数字上看,要更具实际的业务场景,就像不能说10w QPS的秒杀是高并发,而1w的信息流就不是高并发,信息流的处理的逻辑可能比秒杀系统的逻辑还要难上数倍。
	业务都是从 0 做起来的,最重要的是在业务量逐渐变成原来的 10倍、100倍的过程中,是否用到了高并发的处理方法去演进你的系统,从架构设计、编码实现、甚至产品方案等维度去预防和解决高并发引起的问题?而不是一味的升级硬件、加机器做水平扩展。

16、高并发系统设计的目标是什么?(待补充)
先搞清楚高并发系统设计的目标,在此基础上再讨论设计方案和实践经验才有意义和针对性。
宏观目标
高并发绝不意味着只追求高性能,这是很多人片面的理解。从宏观角度看,高并发系统设计的目标有三个:高性能、高可用,以及高可扩展。

1、高性能:性能体现了系统的并行处理能力,在有限的硬件投入下,提高性能意味着节省成本。同时,性能也反映了用户体验,响应时间分别是100毫秒和1秒,给用户的感受是完全不同的。

2、高可用:表示系统可以正常服务的时间。一个全年不停机、无故障;另一个隔三差五出线上事故、宕机,用户肯定选择前者。另外,如果系统只能做到90%可用,也会大大拖累业务。

3、高扩展:表示系统的扩展能力,流量高峰时能否在短时间内完成扩容,更平稳地承接峰值流量,比如双11活动、明星离婚等热点事件。


17、高可用?(待补充)
高可用就是对原来的单体项目的缺陷进行迭代升级、原先的单体服务只要一个功能模块出了问题那么整个服务都变得不可用、为了解决问题将功能模块进行服务的划分单独部署。
集群搭建,是主要的解决思路


扩展篇

Redis (待补充)

  1. 什么是redis
    NoSQL( Not Only SQL ),意即不仅仅是SQL, 泛指非关系型的数据库。Nosql这个技术门类,早期就有人提出,发展至2009年趋势越发高涨。

  2. redis 的热 key 问题

  • 有些 redis 的 热 key 不是突然一瞬间就出现的,而是慢慢的 变多的,比如明星出轨,最开始是一部分人知道,慢慢的大部分人都知道了。所以针对这些即将变热key 的 需要预处理
  • 凭借 经验 区判断 ,哪一个 信息 流量是有可能 成为 热 key
  • 对我们的 key 去做一个 记录统计 ,达到了什么程度 即标记为热key
  • 在 Proxy(代理)层做一个手机

找出 热key , 通过 MQ 的 广播方式 , 去通知 全部的服务 在自己的模块中创建一个 二级缓存去存储这个 热key 和 value 值, 之后查询的时候走自己的缓存即可。
Java面试题_第17张图片
针对与 集群部署的 redis 就需要设计 随机分配 热key + ( 0~2 的随机数 ) , 通过 hash 槽 来分配是哪一个 redis 中写
Java面试题_第18张图片

RocketMQ(待补充)

RabbitMQ(待补充)

Docker(待补充)

什么是 docker ?
我认为docker就是一种轻量级的虚拟机是实现容器化技术的一个应用工具,从操作系统的层面对进程进行封装和隔离,由于独立于宿主和其他的隔离进程 所以也被称为容器

为什么要使用docker,优势有哪些?

  1. 占用资源小,它不需要进行硬件虚拟也不需要运行完整操作系统所带来的额外资源开销,使得docker对资源的利用率更高

  2. 启动快,docker容器应用由于直接运行在宿主的内核上不需要启动完整的操作系统,因此可以做到秒级别的启动

  3. 解决了环境不一致的问题,在别人的电脑上可以运行,但是下拉到我们的电脑上就不可以,而我们的docker是将我们应用和环境一起打包成一个镜像,可以实现我们的环境一致的问题

  4. 高效的迁移和部署,由于docker的特性,我们在部署docker应用项目的时候可以将我们的应用和环境打包成镜像push到仓库中,别的电脑想要使用就直接pull下来,大大减少了我们运维人员部署的成本

  5. 隔离级别的安全,原始的一台服务器中会存在多个应用,会出现环境版本不一致而导致应用之间崩溃问题,比如我一个应用A要用到mysql5.7,应用B要用到mysql8会导致操作起来很麻烦,而且如果mysql8启动需要暂用大量的资源,可能会将其他正常运行的环境杀死以确保它的正常运行,而docker是基于操作系统进程级别的隔离,对进程进行封装和隔离 资源的分配也是交给docker去操作,所以解决了这一问题

说说docker 中三个核心组件 image (镜像) 、 contaier (容器) 、Hub (仓库)

思考docker 怎么开启一个服务?通过开启一个镜像(image )去开启一个服务,而一个服务就是一个容器(contaier ),一个镜像可以开启多个服务,那么镜像从哪里来呢?就从 远程仓库(Hub )里获取 下载到我们的 本地仓库

镜像的操作命令:

容器的操作命令:

传统虚拟机和docker对比

传统:为了模拟线上环境,还得在安装一个vm虚拟机,然后再部署多个linux的操作系统,再在这些操作系统上运行我们的应用,

mysql -> 来宾虚操作系统要资源 -> vm虚拟机 -> 操作系统OS(宿主机) -> 硬件

应用 -> 虚拟操作系统 -> 虚拟机 -> 真正的物理内存

docker:

mysql -> docker引擎 -> 操作系统OS(宿主机) -> 硬件

省略了来宾操作系统 和 虚拟层

应用 -> 虚拟内存 -> 真正的物理内存
Java面试题_第19张图片

Mongodb(待补充)

Seata(待补充)

Canal(待补充)

你可能感兴趣的:(java,面试)