面试-模拟

面试一

算法

反转链表

技术点

1. 为什么使用Mysql8不使用Mysql5

因为Mysql8的性能相对5来说更好,性能几乎是5的两倍,并且8还支持json存储

MySQL5.5版本之前使用MyISAM做为默认存储引擎,5.5之后使用InnoDB做为默认存储引擎

MyISAMInnoDB
索引类型非聚簇索引聚簇索引
支持事务
支持表锁
支持行锁
支持外键
适合操作类型增删改较少的情况增删改较多的情况

非聚簇索引:数据和索引是分开的

聚簇索引:数据和索引存放在一起

2. 索引

索引是一种可以高效获取数据的数据结构,类似于书的目录,我们可以通过目录快速查询到。

常见的索引的实现有hash、二叉搜索树、B树、B+树

B树:每个结点存放主键和数据

B+树:叶节点存放数据、非叶节点存放主键索引

mysql中myISAm和InnoDB都采用的是B+树的数据结构

3. 对于Redis的了解

redis是一个基于内存的键值数据库,它主要是以单线程的方式来执行

5大数据结构 string hash list set zset

5个数据结构

img

string的底层数据结构是:简单动态字符串,类似于Java中的ArrayList,字符串的内容是可以修改的。

hash的底层数据结构是:数组加链表,类似于Java中的HashMap,区别是redis中的hash在扩容时采用的是延迟扩容,客户端请求时将一个元素转移到新HashMap上,这样做的好处是将扩容耗时均摊到了每次请求上。如果长时间没有请求,Redis也会执行扩容。

list的底层数据结构是:压缩列表+双向链表,多个压缩列表直接由前后指针链接成链表。

set的底层数据结构是:数组+链表,和Java中的HashSet类似

zset的底层数据结构是:跳表

4. IOC和AOP

IoC 控制反转的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理,DI是IoC设计思想的实现方式

AOP是面向切面编程,将与业务无关的逻辑分离出来,通过动态代理来增强对象

在spring中动态代理的实现方式有两种,一种是默认的JDK动态代理和CGLib动态代理,JDK与CGLib的区别主要是,JDK是通过实现接口来代理的,而CGLib是通过继承来代理的

5. JVM的垃圾收集算法和收集器器有哪些

标记-复制:将内存空间分成三部分,一共较大的Eden区和两个较小的幸存区,每次分配对象时在Eden区中分配,回收时将Eden区中存活的对象复制到幸存区中,释放掉Eden区供下次分配使用

标记-清除:回收时将需要回收的内存空间释放掉

标记-整理:每次清除时将存活对象移动到一片区域

6. 谈谈Java中的锁

要从锁的种类切入

锁按功能分,主要分为悲观锁乐观锁可重入锁共享锁

悲观锁是数据对外界的修改很保守,认为线程修改数据的几率很大,因此数据每次被修改时都要求线程上锁,比如常见的Synchronized锁就是悲观锁

乐观锁与悲观锁相反,它认为外界对它的修改几率很小,每次线程对数据进行修改时不要求上锁,修改完成后才会检查,例如CAS锁

可重入锁是指一个线程如果已经获得该锁时,可以继续获得该锁。Synchronized和ReentryLock都是可重入锁

共享锁是指同一时间允许多个线程获得锁,例如ReadWriteLock

独占锁是指同一时间只允许一共线程获得锁,例如Synchronized就是独占锁

Synchronized锁的原理

synchronized是Java提供的原子性内置锁,JVM是基于进入和退出Moniter对象来实现同步的。

使用synchroinzed之后,会在编译之后的同步代码块前后加上monitorenter和moniterexit的字节码指令,它依赖的是操作系统底层的互斥锁实现。线程在执行到moniterenter指令时会尝试获得对象的锁,如果对象没有被锁定或者已经获得了锁,锁的计数器+1,此时其他竞争锁的线程会进入等待队列

获得锁的线程在退出或抛出异常时会执行moniterexit指令使计数器-1,当计数器的值为0时则锁释放

Synchronized锁优化机制有哪些

JDK1.6之后Synchronized锁进行了优化,优化机制主要包括包括自旋锁、自适应锁、锁消除、锁粗化、偏向锁和轻量级锁

自旋锁:因为大部分时间锁被占用的时间很短,其他线程在没有竞争到锁时没有必要挂起线程(用户态和内核态的来回上下问切换影响性能)。自旋锁的概念就是让一共锁忙循环避免转入内核态,自旋次数默认是十次,可以修改

自适应锁:自适应锁就是自旋锁,只是它每次的自选次数不是固定的,是根据前一次在这个锁上的自旋时间来决定的

锁消除:锁消除指的是JVM检测到同步代码块完全不存在数据竞争的场景,会对锁进行消除,即不对对象上锁(JIT即时编译器的优化)

锁粗化:线程频繁的获取同一个锁时,虚拟机会将同步块合并为一个锁,线程在执行时只获取一次锁。(JIT即时编译器的优化)

偏向锁:当线程访问同步块并获得锁后,会在对象头和栈帧的锁记录中存储偏向锁的线程ID,之后这个线程再次进入时都不需要加锁和解锁。偏向锁永远只会偏向第一个获得锁的线程,如果有其他线程竞争时,持有偏向锁的线程会释放锁。

轻量级锁:线程进入同步块的时候,JVM将会使用CAS方式来尝试获取锁(替换MarkWord为锁记录指针),如果获取失败,当前线程就尝试自旋来获得锁。

Synchronized锁升级

从偏向锁是如何升级到重量级锁的 - JavaShuo

JDK1.6引入了偏向锁、轻量级锁之后总共有四种锁状态分别是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。

无锁状态是当前没有线程持有该对象的锁

偏向锁状态是指当线程访问同步代码块并获得锁之后,在锁对象头中记录当前线程的ID,之后这个线程再次进入时不需要加锁和解锁。偏向锁只会偏向第一个获得锁的线程。偏向锁只有遇到其他线程尝试获取该锁时,偏向锁会进行撤销,撤销时根据持有线程是否存活来决定是恢复为无锁状态还是升级为轻量级锁。

轻量级锁状态是指所有需要获得锁的线程在获取失败的情况下进入自旋,此时线程不会进入阻塞状态。自旋结束后重新获取锁,如果仍然获取锁失败则锁将升级为重量级锁

CAS

包含三个操作数:变量内存地址V、旧的预期值A、准备设置的新值B

当V=A时才能将V更新为B,否者不更新

缺点:

  • ABA问题:线程在将A修改为B的过程中,当前读取到的指是A,准备修改时还是A,实际上这中间可能会出现其他线程将A修改成B,再修改成A的情况。可以使用添加版本值,每次修改时同时检查预期值和版本值。
  • 自旋CAS长时间不能获取锁,会给CPU带来很大开销
  • CAS只能修改一个变量(解决办法,以引用的方式修改)

7. 进程和线程

  • 进程是计算机资源分配的最小单位、线程是CPU执行的最小单位

  • 进程是程序的一次执行,进程之间的内存是不共享的,而线程之间的内存是可以共享的

为什么Java处理并发采用多线程而不采用多进程

  • 由于进程是资源分配的最小单位,每个进程的创建、销毁、切换都会销毁大量的时间和空间所以进程的数量不能太多
  • 而线程基本不拥有系统资源,只有一些运行时必不可少的资源,可以减少程序并发执行的时间和空间,具有更好的并发性

8.多态

多态是指不同的对象对同一种操作的不同响应,也可以说父类的对象持有子类的引用

java中多态主要有两种表现形式,重写和重载

重写是指子类继承父类后对方法进行扩展

重载是指类中定义了多个同名但方法参数不同的方法

重写的实现原理是方法的动态分派,虚拟机在运行时根据对象的实际类型来确认要调用的方法

重载的实现原理是方法的静态分派,编译器在编译时根据对象的静态类型来确认要调用的方法

10. TCP的可靠性如何保证

TCP的可靠性保证机制主要有七种

  1. 检验和

    发送方将要传输的数据反码相加做为校验字段,接收方接收到数据后对数据进行校验

  2. 序列号

    TCP为每个字节的数据进行编号,发送数据后,将数据包放入重传队列,发送方接收到对应编号的响应后,将数据从重传队列中移除,如果某个数据超时未响应则重传。接收端也可以根据序列号判断数据是否完整。

  3. 确认应答

    发送方在TCP首部添加标志位ACK,如果接收方对按序到达的数据确认后,将返回ACK+1的标识,接收方收到确认后继续发送后续,否则进行重传。

  4. 超时重传

    当发送方发送的报文一定时间内未接收到确认,发送方进行重传。

  5. 链接管理

    三次握手+四次挥手

    三次握手:客户端向服务端发送序列号x,服务端接收到后返回确认序列号x+1以及序列号y,客户端接收后返回确认序列号y+1

    四次挥手:①客户端向服务端发送断开链接,序列号u ②服务端接收后返回确认序列号u+1,客户端收到响应后关闭客户端到服务端的传输通道。TCP链接处于半关闭状态。③服务端数据传输完毕后向客户端发送序列号w和u+1④客户端接收后返回序列号w+1,客户端进入关闭状态撤销传输控制块TCB,服务端收到确认号后也进入关闭状态撤销传输控制块TCB

  6. 流量控制

    接收端处理数据的速度有限时,发送端发送数据过快会导致数据丢包,TCP根据接收端的处理速度来决定发送端的发送速度,这就是流量控制。接收端每次接收数据后在应答报文中带上当前缓冲区的空闲空间大小,发送端根据空间大小来控制数据发送。当空闲空间为0时,发送端停止发送,并定期发送窗口探测,检测是否还有空闲空间

  7. 拥塞控制

    拥塞控制主要解决网络堵塞而产生的丢包问题。主要通过拥塞窗口和慢启动实现。

    拥塞窗口是指:发送方开始发送时将拥塞窗口大小设置为1,往后每次收到接收端的应答报文时拥塞窗口+1,每次发送数据的大小为拥塞窗口和接收端接收窗口大小的最小值决定。

    慢启动是指:发送方一开始发送较小的数据,拥塞窗口初期的值在启动初期指数增长,到达阈值后按线性增长。遇到网络堵塞时按乘法减小,重新开始慢启动。

面试二

技术点

1.谈谈Java中的并发

应该从Thread、Runnable、Callable类切入

java中如果要使用多线程可以通过继承Thread类来实现或者实现Runnable或者Callable接口。启动线程的话是直接调用Thread类的start方法即可

我们一般都是使用线程池来执行多线程任务,因为如果每次执行任务的时候都去创建一个新线程的话,线程创建和销毁都是很消耗资源的。线程池技术就是保持一些线程来不断接收任务并执行,执行结束后回到线程中等待下一个任务。线程池减少了创建和销毁线程的开销,并且提高了响应速度,任务到达时可以直接调度线程执行。

线程池中主要维护着两个队列,一个工作队列,一个线程任务队列。

线程池执行任务的流程:

  1. 外部向线程池提交任务

  2. 判断当前线程池中线程的数量是否达到核心线程数量,如果小于核心线程数,则直接创建新线程执行

  3. 如果大于等于核心线程数,则将任务提交到任务队列中等待空闲线程执行

  4. 如果任务队列满了则,则判断当前线程数量是否大于最大线程数量,如果小于最大线程数量则将创建新线程来执行任务

  5. 如果当前线程数量等于最大线程数量时,则该任务执行失败,执行饱和策略

2. Java中的锁

锁主要分为悲观锁、乐观锁、可重入锁、互斥锁、共享锁

悲观锁是指指数据认为外部对他的修改是很频繁的,要求每次对数据的修改都需要上锁,像java中的Synchronized锁和ReentryLock就是悲观锁

乐观锁是指数据认为外部对他的修改是不频繁的,外部对数据进行访问时不要求上锁,只是在修改的时候会检查,访问期间是否被别的线程修改过。如果访问期间其他线程对数据进行了修改则此次修改失败。CAS就是一个乐观锁

可重入锁是指某个线程在获取到锁之后可以继续对这个锁上锁。Synchronized和ReentryLock都是可重入锁

互斥锁是指一个锁在任意时刻只能被一个线程持有

共享锁是指一个锁可以在同一时间内被多个线程获取,例如juc下的读写锁中的读锁

volatile也是java中一种轻量级的同步机制。volatile能保证有序性和可见性,但不保证原子性。也就是说使用volatile变量来同步的话,变量的修改不能依赖原来的值才行。

Synchronized是Java内置的原子锁,它是依靠虚拟机实现的锁,而jvm是基于进入和退出对象的监视器实现的。

编译器会在同步代码块的前后插入monitorenter和monitorexit两条字节码指令。虚拟机执行到monitorenter时会先尝试获取对象的锁,获取对象的锁成功后才会继续执行,否者进入等待队列。每个monitor中都有一个计数器,线程只有在计数器为0时才能获取锁,获取锁成功后计数器+1;虚拟机在执行monitorexit时将计数器-1,直到计数器为0即释放锁。

1.6之前Synchronized是一个重量级锁,不过在1.6之后对Synchronized进行了优化。对锁进行了优化

优化手段主要有,加入锁升级机制、锁消除、锁膨胀

锁升级是指虚拟机将锁分为四个状态,无锁状态、偏向锁、轻量级锁和重量级锁

3.虚拟机的垃圾收集

在java中所有几乎所有引用数据类型的对象都分配在堆中。垃圾收集的主要作用就是判断哪些对象需要回收然后对需要回收的对象进行回收。

判断回收的方式主要有两种,一种是引用计数法,一种是可达性分析。引用计数法就是每一个对象有一个计数器,当这个对象被其他对象引用时计数器+1,当引用断开时计数器-1。但是这种方式存在环形引用的问题,就是两个对象互相引用的时候计数器始终大于1,这种会造成内存泄漏问题。

常用的hotspot虚拟机采用的时第二种可达性分析,就是每次在需要回收时,将一部分对象做为根节点,然后从根节点出发,如果无法到达某个对象则说明该对象需要回收。

常用来做为GCROOT的对象有

  • 静态类型的对象
  • 局部变量表
  • 常量引用的对象
  • 一些基本数据类型的Class对象、和系统类加载器
  • Synchronized同步锁持有的对象

大部分收集器是基于分代收集理论实现的,分代收集理论是指大部分对象都是朝生夕灭的

为什么要选择他们公司

自己的优缺点

反问环节

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shenyang1026

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值