记一次java面试问题回答

前言

坐标北京,两年java经验,看书看博客当时理解的知识点,过一会儿或者在面试的时候很难给面试官讲清楚,一是忘的快,二是表达能力欠佳。故在博客上记录下来,提高对面试知识点的印象和逻辑表达能力。ps:记得的都写下来了。

正文

面试官:synchronized和ReentranLock有什么区别?

答:synchronized是java语言层面提供的一个关键字,而ReentranLock是java的一个类,此外的话,ReentranLock它可以用Condition对象创建多个等待队列,而synchronized锁定的对象只有一个等待队列。ReentranLock比较灵活,可以响应中断,而synchronized里的代码要么是发生异常了要么是全部执行完才能退出,ReentranLock支持等待一定的时间。

 

面试官:HashMap的原理是什么?

答:HashMap它的底层数据结构是数组+链表,我们再调用它的put方法的时候,首先,它会根据我们传进去的key的hashCode()方法得到一个hash值,然后根据这个hash值通过一个数组下标定位算法定位到数组位桶的下标,在取得该位置的第一个元素进行比较,先比较他们的hash值是否相同,若相同,才继续判断是否equals,否则继续判断下一个node。当没有node相等的时候,会在该位置新建一个node,并把next指向之前的那些node节点,使发生hash冲突的元素保持链表的结构(jdk1.8中当碰撞node数达到默认的8,会将链表变为红黑树,从而提高查询的效率),最后判断时候达到初始hashEntry数组的规定容量(默认16*0.75),达到,则扩容。

追问:你刚刚说了负载因子,它有什么用呢?为什么要设置成0.75呢?

答:负载因子的话,主要目的还是为了避免hash碰撞嘛,设置成0.75的话,这个是jdk的设计者们研究出的一个数值,它能使时间和空间达到一个很好的平衡嘛。其余就不知道了。。。

 

面试官:HashMap是线程安全的么?

答:不是

追问:那有线程安全的map吗?

答:有,HashTable和ConcurrentHashMap。

追问:他们有什么区别呢?

答:首先,HashTable的定义是同步容器类,而ConcurrentHashMap定义则是并发容器类,从定位上来说就可以看出两者在并发环境下的效率;HashTable它里面的方法基本都是以synchronized修饰的,也就是说同一时刻只能有一个线程能访问HashTable,在高并发环境中效率非常低下。而ConcurrentHashMap它可以允许多个线程同时读,一定数量的线程同时写(默认并发度16,即默认下最多可以允许16个线程同时执行put方法)

追问:那ConcurrentHashMap是怎么实现的呢?

答:它的实现的话主要是使用了分段锁的机制,它的内部有一个叫segment的内部类,这个内部类是继承于ReentranLock的,也就是相当于一把锁了,ConcurrentHashMap内部维护了一个segment数组。我们调用它的get方法的时候他是不会上锁的,这个实现就能达到允许n个线程同时读数据,我们调用它的put方法的时候,才会去上锁。那它默认de的segment的数组的长度是16,也就是说,默认情况下,我们最多可以有16条线程同时执行put方法(16条线程均匀的分配到了16个segment上)。

追问:你这是jdk几的实现?

答:jdk1.6.

面试官:哦哦,jdk8不是这么实现的哈。

我:emmmm。。。

面试官:你刚刚提到了ReentranLock,你能给我讲一下它是怎么实现的么?

答:ReentranLock的话它的实现是基于AQS完成的,其实AQS是java中一个非常重要的类,理解了它的话基本其他的一些同步组件类都很容易弄懂了。那,AQS的话呢它主要有一个状态变量State,用于给不同的同步组件实现各自的一个同步语义,比如说ReentranLock用这个state来表示线程获取到的锁的次数,那在我们调用它的lock方法的时候呢,它会尝试着以cas的方式(AQS提供的方法)把这个state的值从0变成1,如果改变成功了,那么就代表当前线程获取锁成功了,然后他会设置当前线程为状态的持有者,以支持重入。如果改变失败,那么就代表别的线程获得了锁,但是会继续判断那个获得了锁的线程是不是我自己。如果是我自己,就继续把state的值加1,如果不是,就进入AQS维护的同步队列中等待。我们调用它的unLock方法的时候则是会把state值减1,减到0的时候,其他的线程就又可以竞争这个state了。

面试官:恩,看来是看过一些源码的哈,java中读写锁实现太麻烦了,你能不能自己设计一个读写锁呢?有思路么?

我:emmm。。。。不同清楚。。

面试官(微笑):可以用信号量和一些其他的同步组件去实现的哈。(问题过。)

面试官:事务了解吗?ACDI是什么?

答:acdi就是事务的四个特性嘛,原子性,一致性,隔离性,持久性。其中针对隔离性数据库会提供4个隔离级别来解决一些问题,那首先我们得知道若没有隔离级别,会有什么问题。

1.脏读,脏读就是一个事务读到了另一个事务未提交的数据,比如我事务b把一个数据从1改成了2,这时,我事务a读到了这个数据为2,但是事务b由于某种原因,回滚了事务。此时脏读就产生了。

2.不可重复读:不可重复读就是指在一个事务范围内,两次或多次查询数据期间,其他事务将数据改了,导致前后多次查询数据的结果不一样。比如事务a开始查询一个数据为1,事务b把这个数据改为了2,这时事务a再去查询数据为2,前后两次查询同一个数据,结果不一样。

3.幻读:幻读的重点在于insert操作,比如事务a现在要把一张表中50个数据(性别为男)改为女,在事务a修改的期间,事务b向这个表中插入了一条数据(性别为男),ok,然后事务a想查询一下修改的结果,却发现还有一条数据未被修改过来。就像发生了幻觉一样,这就叫幻读。

4.丢失更新:比如事务a先将数据1改成了2,这时,事务b又将数据2改成了3,然后事务a去查询数据,发现自己做的修改没了,查询到的数据是3.这就是丢失更新

面试官:那事务的隔离级别是怎么实现的呢?

答:是根据行锁来实现的,数据库中按粒度来分的话,有表锁和行锁,按模式分又有共享锁和排他锁。我发现一个特点,就是支持行锁的数据库存储引擎也支持事务,不支持行锁的存储引擎,不支持事务。那么,行锁是怎么实现隔离级别的呢?

1.在未提交读这个隔离级别下:

事务在读数据的时候,不上锁

事务在写数据的时候,会为数据上一个行级的共享锁,直到事务结束释放。

2.在提交读这个隔离级别下:

事务在读数据的时候,会为数据上一个行级共享锁,但是读完立即释放,锁持有的时间短;

事务在写数据的时候,会为数据上一个行级排他锁,直到事务结束后释放。

3.在可重复读隔离级别下:

事务在读数据的时候,会为数据上一个行级共享锁,直到事务结束后释放,锁持有时间长;

事务在写数据的时候,会为数据上一个行级排他锁,直到事务结束后释放。

4串行隔离级别下:

读数据上表级的共享锁,写数据上表级的排他锁。

ps:这个回答只是理论上来说的,各个数据库的实现都很复杂,我也是面试完之后再回来好好看了一下的。但是面试的时候回答到这些已经不错了,无奈面试官懂的太多了,他还是继续往下问

面试官:你刚刚说事务是为数据上的锁,你确定吗?

我:你都这么问了,应该不是吧。。。

面试官:事务是为索引加的锁哈。mysql默认的隔离级别能解决幻读问题么?

我:它可以解决不可重复读和脏读,但是不能解决幻读。

面试官:你确定???

我:emmm。。。。。确定。

面试官:是可以的哈,用了间隙锁。

ps:回去一查,确实是可以解决的,其实仔细想想也知道,如果问题都没法解决那为什么还要默认使用这个级别呢?

面试官:mvcc知道么?

我:不太清楚。

面试官:你还知道数据库的那些知识?

我:索引吧,我知道索引它是使用的b+树的形式,至于为什么要使用这种数据结构,主要是为了减少磁盘io次数,因为数据库的瓶颈就是磁盘的io嘛。而b+树的结构符合那种矮矮胖胖的形式,高度很低,那树的高度低的话,磁盘的io次数也就低了。

面试官:b+树是二叉树么?

我:不是,它是一种多叉树,如果是二叉树的话,它的高度就很高了。

面试官:索引是顺序的还是乱序的?

我:emmm。。。应该是顺序得把。

面试官:恩,因为在磁盘中,顺序的查找只需要沿着那个啥往下找就行了,而乱序的就是一下崩这里,一下崩哪里。

我:哦。。。。明白了,明白了,长知识了。。

面试官:b+树是怎么排序组合索引的?比如我建了一个组合索引(A,B)我按B的排序去找能找到吗?

我:不能找到,要按照最左匹配原则查找。

面试官:那最左匹配原则在b+树上是怎么样的呢?比如现在有A 1、2、3 ,B  1、2、3    ,在b+树上他是怎么排的?是A1、A2、A3 还是B1、B2、B3这么排的?(脑补吧哈哈)

我:应该是A1、A2、A3(瞎说的,我都不明白他说的啥)

面试官:恩,你再做几道题,待会儿还有个二面哈。

 

二面。卒,全是问的一些项目的,包括一些分布式的东西,我说上家公司没接触过分布式的一些东西,但是我也有了解,最后,回去等消息吧。。。我们内部再合计合计。。。

 

写在结束

现在大多数公司都是要求分布式啊,微服务啊相关的技术人才,比如dubbo 、zookeerper、springBoot、springCloud、redis、mq等等,自己也确实缺乏这些方面的认识,仅仅停留在了解,知道他们是干嘛的,解决了哪些问题。实际项目中并没有使用过,也不知道其实现原理。这次面试,虽然没过,但是和一面的技术聊的蛮开心的,在一些问题的深度上面还有待提高。把自己还记得的一些问题记录下来,加深一些印象,期待下一次面试。溜了溜了

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 Java 面试常见问题回答: 1. Java 中的四种访问修饰符是什么? 答:Java 中的四种访问修饰符分别是 public、private、protected 和 default。 2. 什么是 JVM? 答:JVM 是 Java Virtual Machine(Java 虚拟机)的缩写,它是 Java 程序的运行环境。 3. Java 中的多态性是什么? 答:Java 中的多态性指的是同一个方法可以被不同的对象调用并产生不同的结果。 4. 什么是 Java 中的 final 关键字? 答:final 关键字可以用来修饰变量、方法和类。如果一个变量被修饰为 final,它就不能被更改;如果一个方法被修饰为 final,它就不能被重写;如果一个类被修饰为 final,它就不能被继承。 5. 什么是 Java 中的异常? 答:Java 中的异常指的是程序运行过程中发生的错误或意外情况,如空指针、数组越界等。 6. Java 中的线程是什么? 答:Java 中的线程是程序执行的最小单位,它可以独立地执行代码。 7. Java 中的集合类有哪些? 答:Java 中的集合类包括 List、Set、Map 等。 8. 什么是 Java 中的反射? 答:Java 中的反射是指在运行时通过反射机制获取类的信息,包括类名、属性、方法等。 9. 什么是 Java 中的序列化? 答:Java 中的序列化指的是将对象转换为字节序列的过程,以便将其存储到文件或通过网络传输。 10. Java 中的 static 关键字是什么? 答:Java 中的 static 关键字可以用来修饰变量和方法。如果一个变量被修饰为 static,它就是类级别的变量,所有对象共享这个变量;如果一个方法被修饰为 static,它就是类级别的方法,可以直接通过类名调用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值