【打卡day06】每天学习10道java面试题

目录

1.常见的Exception、Error,区别是什么?

2.MySQL索引底层结构原理?

3.线程同步的几种工具,交替打印ABC?

4.MyBatis和MyBatisPlus区别?

5.ThreadLocal?

6.缓存击穿、穿透、雪崩,是什么,怎么解决?

7.关系型数据库和非关系型有什么区别?

8.数据库:order by、group by、having语句的区别?

9.红黑树?

10.Java 中 IO 流分为几种?


1.常见的Exception、Error,区别是什么?

Exception大多情况下是可预料的意外情况(指的是具体的原因),通常可以对其进行捕获,进行相应的处理;而Error绝大情况下是不可预料的(指的是具体的原因),通常无法进行捕获并且会导致程序终止

内容图片参考链接:Error 和 Exception 的区别?_任重而道远丶的博客-CSDN博客_error和exception的区别

2.MySQL索引底层结构原理?

【底层结构原理】采用了B+树的结构,并且叶子节点之间是通过双向链表的方式进行连接。B+树的高度对应的是磁盘IO的次数,它只在叶子节点存储数据,数据可以是记录id(非聚簇索引)或者是整条记录(聚簇索引)。之所以只在叶子节点存储数据,是为了让非叶子节点存储更多的索引从而降低树的高度即减少磁盘IO的次数(mysql中数据读取的基本单位是页,所以B+树的每个节点对应的就是一个页大小的磁盘块),之所以采用双向链表的方式是为了方便范围查询。非主键索引构建的索引B+树的叶子节点通常是记录的普通索引和主键,因此在查询字段中包含有非索引字段的数据时,通常需要先查询到主键,然后再通过回表操作(查询主键索引树)查到符合条件的数据;为提升查询效率,我们应尽量去减少查询中回表的频率。

3.线程同步的几种工具,交替打印ABC?

【线程同步工具】

CountDownLatch :CountDownLatch 中有一个初始值,通过调用countDown可以减少该值,直到该值减少到0,所有线程才会同时开始往下执行。

Semaphore :用于控制同时访问某资源,或同时执行某操作的线程数目。

CyclicBarrier:有点类似同步屏障的概念,即用于多个线程多次迭代时进行同步,在一轮任务中,任何线程完成任务后都在 barrier 上等待,直到所有其他线程也完成任务,然后一起释放,同时进入下一轮迭代。

ps:CountDownLatch中的同步只能利用一次,而CyclicBarrier可以反复使用。

【交替打印ABC】

 //交替打印通过CyclicBarrier实现
 public class TestCyclicBarrier {
     public static void main(String[] args) throws InterruptedException {
         CyclicBarrier barrier = new CyclicBarrier(3);
         while(true) {
             new Thread(() -> {
                 System.out.println('A');
                 try {
                     barrier.await();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } catch (BrokenBarrierException e) {
                     e.printStackTrace();
                 }
             }).start();
             new Thread(() -> {
                 System.out.println('B');
                 try {
                     Thread.sleep(100);
                     barrier.await();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } catch (BrokenBarrierException e) {
                     e.printStackTrace();
                 }
             }).start();
             new Thread(() -> {
                 System.out.println('C');
                 try {
                     Thread.sleep(200);
                     barrier.await();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } catch (BrokenBarrierException e) {
                     e.printStackTrace();
                 }
             }).start();
             Thread.sleep(3000);
         }
     }
 }

4.MyBatis和MyBatisPlus区别?

【MyBatis】

  • 所有SQL语句全部自己写

  • 手动解析实体关系映射转换为MyBatis内部对象注入容器

  • 不支持Lambda形式调用

【MyBatisPlus】

  • 强大的条件构造器,满足各类使用需求

  • 内置的Mapper,通用的Service,少量配置即可实现单表大部分CRUD操作

  • 支持Lambda形式调用

  • 提供了基本的CRUD功能,连SQL语句都不需要编写

  • 自动解析实体关系映射转换为MyBatis内部对象注入容器

内容参考链接:Mybatis 和 Mybatis Plus 的区别_小码飞飞的博客-CSDN博客_mybatisplus和mybatis的区别

5.ThreadLocal?

【简介】

ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。通常被private static 修饰。

  • 因为每个 Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用。这是也是 ThreadLocal 命名的由来。

  • 既然每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就不存在多线程间共享的问题

新版本的ThreadLocal:每个线程都拥有自己的ThreadLocalMap,如果用ThreadLocal修饰了某个变量,那么该变量的实例将作为key,值作为value存入ThreadLocalMap中。

老版本的ThreadLocal:每个ThreadLocal修饰的变量都有用ThreadLocalMap,线程作为key,值作为value存入ThreadLocalMap中。缺点是:存储的key-value键值对随线程数增多而增多;线程销毁时ThreadLocalMap依旧存在,一定程度上浪费内存。

【使用场景】Spring MVC架构在控制层拦截请求时将用户信息存入ThreadLocalMap、以及常见的cookie、session、数据库连接池等需要数据隔离的场景。

【实现原理】

  1. ThreadLocal类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals,每个线程都有一个属于自己的ThreadLocalMap。

  2. ThreadLocalMap内部维护了一个Entry数组,每个Entry代表了一个完整的对象,key是ThreadLocal.threadLocalHashCode(ThreadLocal类的一个常量,每一个ThreadLocal对象都会生成一个)的弱引用,value是ThreadLocal的泛型值(变量值)。

  3. 每个线程在往ThreadLocal里设置值的时候,都是在往自己的线程中的ThreadLocalMap里存,读也是以某个ThreadLocal.threadLocalHashCode作为引用,在自己的map中获取值,因此实现了线程隔离。

  4. ThreadLocal本身(变量本身)不存储值,它只是作为一个key来让线程往ThreadLocalMap里取值。

【关于内存泄露】

  1. ThreadLocalMap的key为什么要以ThreadLocal的弱引用,因为弱引用是在垃圾回收时就会被清理;如果key为强引用,那么当一个使用了ThreadLocal变量的方法结束时,按理说该方法的实例应该全部被回收,但由于ThreadLocalMap是属于线程的,它依旧还在,以及他的key如果是强引用,会导致该结束的方法的ThreadLocal修饰的变量实例得不到回收从而导致内存泄露。

  2. ThreadLocalMap的key既然是弱引用,那么会出现key被回收了,而value还在导致的内存泄露,该问题的解决是每次使用完ThreadLocal后,及时调用remove()方法释放内存空间。

ps:revome()方法源码步骤:1.计算对象实例算出hashcode得到key 2.计算数组下标位置,若该位置的key为null(通过get可以获取key),则删除对应的Entry。

散列方法:ThreadLocal每次创建,都会计算出一个ThreadLocal.threadLocalHashCode常量,该常量每次生成会以斐波那契数作为hash增量,带来的好处是分布非常均匀。冲突解决办法采用了开放地址法。

6.缓存击穿、穿透、雪崩,是什么,怎么解决?

【缓存击穿】

问题描述:一个并发访问量比较大的key在某个时间过期,导致所有的请求直接打在DB上。

两种解决方案:1.加锁更新,比如请求查询A,发现缓存中没有,对A这个key加锁,同时去数据库查询数据、写入缓存,再返回给用户,这样后面的请求就可以从缓存中拿到数据了。2.将过期时间组合写在value中,通过异步的方式不断的刷新过期时间,防止此类现象。

【缓存穿透】

问题描述:缓存穿透指的查询缓存和数据库中都不存在的数据,它将导致不存在的数据每次请求都到存储层去查询,失去了缓存保护后端存储的意义。

两种原因:1.自身业务代码问题 2.恶意攻击,爬虫造成空命中

两种解决方案:1.缓存空值/默认值 2.布隆过滤器

ps:.缓存空值也会出现问题:1.空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间(如果是攻击,问题 更严重),⽐较有效的⽅法是针对这类数据设置⼀个较短的过期时间,让其⾃动剔除。2.缓存层和存储层的数据会有⼀段时间窗⼜的不⼀致,可能会对业务有⼀定影响。例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存 层和存储层数据的不⼀致。这时候可以利⽤消息队列或者其它异步⽅式清理缓存中的空对象。

【缓存雪崩】

问题描述:某一时刻发生大规模的缓存失效情况,例如缓存服务器宕机、大量key在同一时间过期,这样的后果就是大量的请求直接打到DB上,可能导致整个系统的崩溃,称为雪崩。

解决方案:提高缓存可用性(集群部署、多级缓存等)、合理设置过期时间(均匀过期、热点数据永不过期)、熔断降级(服务熔断:当缓存服务器宕机或超时响应时,为了防⽌整个系统出现雪崩,暂时停⽌业务 服务访问缓存系统。服务降级:当出现⼤量缓存失效,⽽且处在⾼并发⾼负荷的情况下,在业务系统内部暂时舍弃对⼀些⾮核⼼的接⼜和数据的请求,⽽直接返回⼀个提前准备好的 fallback(退路)错误处理信息。

内容参考来自三分恶大佬,推荐关注【三分恶】公众号,向三分恶大佬致敬,大佬主页地址:三分恶的博客_CSDN博客-JavaSE,BUG笔记,Vue.js领域博主

7.关系型数据库和非关系型有什么区别?

关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织;非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。

【关系型数据库】

优点:1、易于维护:都是使用表结构,格式一致;2、使用方便:SQL语言通用,可用于复杂查询;3、复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。

缺点:1、读写性能比较差,尤其是海量数据的高效率读写;2、固定的表结构,灵活度稍欠;3、高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。

【非关系型数据库】

优点:1、格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。2、速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;3、高扩展性;4、成本低:nosql数据库部署简单,基本都是开源软件。

缺点:1、不提供sql支持,学习和使用成本较高;2、无事务处理;3、数据结构相对复杂,复杂查询方面稍欠。

内容参考:关系型数据库和非关系型数据及其区别_原野的稻草人的博客-CSDN博客_关系数据库和非关系数据库区别

8.数据库:order by、group by、having语句的区别?

  • order by 从英文里理解就是行的排序方式,默认的为升序。 order by 后面必须列出排序的字段名,可以是多个字段名。

  • group by 从英文里理解就是分组。必须有“聚合函数”来配合才能使用,使用时至少需要一个分组标志字段。(像sum()、count()、avg()等都是“聚合函数”)

  • where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行。

  • having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having 条件显示特定的组,也可以使用多个分组标准进行分组。

9.红黑树?

推荐链接:硬核图解面试最怕的红黑树【建议反复摩擦】_敖 丙的博客-CSDN博客_红黑树 难度

10.Java 中 IO 流分为几种?

Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的.

字符流和字节流是根据处理数据的不同来区分的。字节流按照8位传输,字节流是最基本的,所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。

1.字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;

2.节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。

读文本的时候用字符流,例如txt文件。读非文本文件的时候用字节流,例如mp3。理论上任何文件都能够用字节流读取,但当读取的是文本数据时,为了能还原成文本你必须再经过一个转换的工序,相对来说字符流就省了这个麻烦,可以有方法直接读取。

字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节, 操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!

参考链接:Java 中 IO 流分为几种?BIO,NIO,AIO 有什么区别?_单灿灿的博客-CSDN博客_io流有哪几种

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值