面试汇总

面试题汇总



一、数据结构

  1. 二叉树的遍历

前序(根、左、右)
中序(左、根、右)
后序(左、右、根)
参考:https://www.cnblogs.com/llguanli/p/7363657.html
2.


二、网络

  1. HTTP几种请求类型
methord 描述
GET 请求指定页面信息,并返回实体主体
HEAD 类似于GET请求,只不过返回的响应中没有具体的内容,用于获取报头
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。(全部取代)
PATCH 从客户端向服务器传送的数据取代指定的文档的内容。(部分取代)
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS 允许客户端查看服务器的性能。
TRACE 回显服务器收到的请求,主要用于测试或诊断。
  1. 常见响应码
响应码 说明 备注
200 OK 请求已成功
201 Created 资源已创建
204 No Content 请求已成功,但无返回内容
304 Not Modified 缓存有效
400 Bad Request 语义有误,当前请求无法被服务器理解,请求参数错误
401 Unauthorized 当前请求需要用户认证(登录)
403 Forbidden 用户已认证(登录),但权限不足
404 Not Found 请求源未在服务器上被发现
405 Method Not Allowed 请求方法不能被用于请求相应的资源,如使用PUT方法访问只接受POST方法的API
500 Internal Server Error 服务端内部错误
502 Bad Gateway 网关错误
504 Gateway Timeout 网关超时
  1. GET、POST区别

根据HTTP协议规定,GET请求用于信息获取,应该是安全的和幂等的(无副作用),虽然获取的结果会变化,但请求不会有任何副作用。

领域 GET POST
作用 查询数据 创建、修改数据
长度限制 HTTP协议中无限制
但由于各个浏览器有自己的对于URI的长度限制
因此会有长度限制
无限制
后退、刷新操作 无影响 会重复提交数据
前端哪些解决方案
后端哪些解决方案
请求过程 TCP三次握手,并发送数据
1. 浏览器请求TCP连接
2. 服务器响应TCP连接
3. 浏览器确认TCP连接,并发送GET请求头和数据
4. 服务器响应200,OK
TCP三次握手后,发送数据
1. 浏览器请求TCP连接
2. 服务器响应TCP连接
3. 浏览器确认TCP连接,并发送POST请求头
4. 服务器返回100 continue响应
5. 浏览器发送POST的数据
6. 服务器响应200,OK
缓存 可以缓存 无法缓存
历史 数据会保留在浏览器历史中 数据不会有历史
数据类型 ASCII字符 无限制
安全性 差,数据暴露,遗留历史 数据不显示,无历史记录
  1. 描述一次HTTP请求全过程

(1) URL部分:协议(HTTP\HTTPS)、DNS域名解析过程、资源路径

DNS解析过程:www.google.com

  1. 浏览器检查自身缓存,域名所对应IP地址
  2. 浏览器缓存未命中,检查操作系统缓存(hosts文件),是否存在域名对应IP地址
  3. hosts文件未命中,请求LDNS(本地域名服务器)查询域名
  4. LDNS查询本地域名解析缓存结果,命中则返回
  5. LDNS未命中缓存,继续向上级DNS服务器查询,直至查询返回域名信息

(2) TCP/IP、DNS、HTTP、HTML、渲染


三、操作系统

  1. Linux常用命令

ls、tail -f、less、more、pwd、rm -rf、mv、cp、find、chmod、chown、grep、top、cat、ps -ef|grep tomcat
2.


四、设计模式

  1. 有哪些设计模式

分为三类
创建型模式:单例、工厂、抽象工厂、建造者模式、原型模式
结构型模式:适配器模式、过滤器模式、桥接模式、组合模式、装饰器模式、外观模式、代理模式、享元模式
行为型模式:责任链模式、命令模式、解释器模式、迭代器模式、观察者模式、状态模式、空对象模式、策略模式、模板模式、访问者模式、反应器模式
2.


五、Java基础

  1. 锁的分类
    • 公平锁、非公平锁
      公平锁是指多个线程按照申请锁的顺序来获取锁。
      比如:ReentrantLock,默认是非公平锁,也可以通过构造函数传入公平模式创建公平的可重入锁。而Synchronized只是非公平锁,谁拿到就是谁的,跟申请顺序无关。
    • 排他锁、共享锁
      排他锁,也叫互斥锁、写锁是指该锁一次只能被一个线程所持有,是一种概念。
      共享锁是指该锁可被多个线程所持有,是一种概念。
      ReentrantLock是排他锁,ReadWriteLock,其中读是共享锁,写是排他锁。读写,写读 ,写写的过程是互斥的。Synchronized只能是排他锁。
    • 可重入锁、读写锁
      ReentrantLock,可重入锁,是排他锁的一种实现,加锁后其他线程无法再获取这个加锁对象。ReentrantLock是基于AQS实现,AQS的实现基础即为CAS。
      读写锁是一种自旋锁,即不断重试。比如读锁存在,尝试进行写锁时,会不断重试,直至读锁释放,才可以获取到写锁。或当在进行写加锁时,读会不断重试,直至写锁释放。读与读之间不会互斥,会共享锁。
      为了防止饿死情况,即读一直存在,写锁拿不到,会在写尝试加锁时,禁止后续的读再拿到共享锁,而是等待读锁释放,由等待的写锁进行操作。适用于读多写少的情况。
    • 乐观锁、悲观锁
      是指看待并发同步的角度。
      乐观锁:认为对于同一个数据的并发操作,一般是不会发生修改的。
      悲观锁:认为对于同一个数据的并发操作,一定会发生修改。
      乐观锁的实现方案:CAS算法(compare and swap)、自旋
      悲观锁的实现方案:Synchronized、ReentrantLock、数据库行锁、表级锁等
    • 分段锁
      分段锁是一种设计,比如ConcurrentHashMap,采用了分段锁方式实现高效的并发操作。
      ConcurrentHashMap结构设计有16个Segment,Segment结构即为HashMap,同时继承了ReentrantLock,从而实现最高支持16个并发操作。
    • 自旋锁
      一种锁设计,是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
      优点:自动重试获取锁,不会阻塞,因为线程一直是active状态,不断循环尝试获得锁,因此无需线程上下文切换。
      缺点:可能会导致busy-waiting忙等待,不公平的自旋锁可能会导致线程饥饿,一直获取不到锁。
      实现原理:CAS思想,如果compareAndSwap成功,则尝试加锁成功,否则继续循环。
  2. Synchronized的同步原理

  synchronized关键字可以修饰普通方法、静态方法、代码块,主要分为代码块的同步和方法的同步两种,两种同步底层原理相同,但是实现方式稍有不同。
底层原理
  Monitor对象,任何同步的访问必须先获取monitor对象,才能进行操作,然后再释放monitor对象。
代码块的同步:
  指令控制,monitorenter,monitorexit
monitorenter:
  每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

  1. 如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。
  2. 如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数进行加1。
  3. 如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

monitorexit:
  执行monitorexit的线程必须是objectref所对应的monitor的所有者。
  指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。

方法的同步:
  方法的同步分为普通方法和静态方法。静态方法属于类,因此需要获取类锁,每个类只有一个类锁,因此同步的静态方法只能获得锁后调用,非同步的方法可以随意调用。每个类可能会实例化为很多实例,每个实例有一个对象锁,不同对象之间加锁不同。
  可以认为类锁也是对象锁,其实类也是一个Class对象,所有静态的都是走的类这个对象。类锁和方法锁之间不冲突,互相无影响。
  方法的同步采用的是ACC_SYNCHRONIZED标记,即标志此方法为同步方法。
  当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。
  锁就存在于Java对象头中。

  1. Java对象头

  Java对象在内存中保存,由三部分组成:Java对象头,实例数据,对齐填充字节。
  Java对象头由三部分组成:Mark Word,指向类的指针,数组长度(只有数组对象才有)。
以下为Mark Word关于锁的状态。默认无锁,标志位为01。
Mark Word

JVM一般是这样使用锁和Mark Word的:

  1. 当没有被当成锁时,这就是一个普通的对象,Mark Word记录对象的HashCode,锁标志位是01,是否偏向锁那一位是0。
  2. 当对象被当做同步锁并有一个线程A抢到了锁时,锁标志位还是01,但是否偏向锁那一位改成1,前23bit记录抢到锁的线程id,表示进入偏向锁状态。当对象被当做同步锁并有一个线程A抢到了锁时,锁标志位还是01,但是否偏向锁那一位改成1,前23bit记录抢到锁的线程id,表示进入偏向锁状态。
  3. 当线程A再次试图来获得锁时,JVM发现同步锁对象的标志位是01,是否偏向锁是1,也就是偏向状态,Mark Word中记录的线程id就是线程A自己的id,表示线程A已经获得了这个偏向锁,可以执行同步锁的代码。
  4. 当线程B试图获得这个锁时,JVM发现同步锁处于偏向状态,但是Mark Word中的线程id记录的不是B,那么线程B会先用CAS操作试图获得锁,这里的获得锁操作是有可能成功的,因为线程A一般不会自动释放偏向锁。如果抢锁成功,就把Mark Word里的线程id改为线程B的id,代表线程B获得了这个偏向锁,可以执行同步锁代码。如果抢锁失败,则继续执行步骤5。
  5. 偏向锁状态抢锁失败,代表当前锁有一定的竞争,偏向锁将升级为轻量级锁。JVM会在当前线程的线程栈中开辟一块单独的空间,里面保存指向对象锁Mark Word的指针,同时在对象锁Mark Word中保存指向这片空间的指针。上述两个保存操作都是CAS操作,如果保存成功,代表线程抢到了同步锁,就把Mark Word中的锁标志位改成00,可以执行同步锁代码。如果保存失败,表示抢锁失败,竞争太激烈,继续执行步骤6。
  6. 轻量级锁抢锁失败,JVM会使用自旋锁,自旋锁不是一个锁状态,只是代表不断的重试,尝试抢锁。从JDK1.7开始,自旋锁默认启用,自旋次数由JVM决定。如果抢锁成功则执行同步锁代码,如果失败则继续执行步骤7。
  7. 自旋锁重试之后如果抢锁依然失败,同步锁会升级至重量级锁,锁标志位改为10。在这个状态下,未抢到锁的线程都会被阻塞。

以上即为JVM使用锁的过程。

  1. Synchronized与ReentrantLock的区别
领域 Synchronized ReentrantLock
条件 只有一个 可以使用condition组合灵活控制
顺序 固定非公平锁 公平锁、非公平锁都支持
锁超时 阻塞等待 可以尝试加锁,可以控制等待时间,可以中断
操作 加锁 加锁、finally解锁
  1. 原子类-Atomic

  比如:AtomicInteger、AtomicLong等。线程安全的类。
AtomicInteger中会调用Unsafe类下的CompareAndSwapInt方法,通过CAS的思想与自旋的方式,实现同步非阻塞的方式。

  1. AQS

  抽象类:AbstractQueuedSynchronizer,抽象的队列式同步器,定义了一套多线程访问共享资源的同步器框架,是java.util.concurrent的核心。

  1. CAS

  CAS指令,CPU指令,compare and swap,Unsafe类下的cas操作会在虚拟机中进行特殊处理,处理为一条指令信息,通过硬件原子操作实现非阻塞同步,通过冲突检测和操作完成。
  CAS需要三个操作数,分别是内存位置(用V表示),旧的预期值(用A表示)和新值(用B表示)。CAS执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则它就不执行。
  CAS+自旋重试,从而实现乐观锁式的操作。

  1. Unsafe类

  Unsafe类是java中非常特别的一个类。它名字就叫做“不安全”,提供的操作可以直接读写内存、获得地址偏移值、锁定或释放线程。
  通过正常途径是无法获得Unsafe实例的,首先它的构造方法是私有的,然后,即使你调用它的getUnsafe方法,也会抛出SecurityException,因为getUnsafe方法中检查该CallerClass(调用方)是不是由系统类加载器BootstrapClassLoader加载。除非通过反射机制,才能跳过安全检查。
功能:

  • 读功能:读取内存中的某块数据
  • 写功能:
  • CAS操作:compareAndSwapXXX,原子操作,cpu在执行cas时对这一块内存是独占排他的。在并发包中很多操作真正执行的也是cas,并发包中的类并发性能比使用 synchronized 关键字好也在于此:锁的粒度小了许多并且少了线程上下文切换。
  • park、unpark:线程挂起、恢复线程。(比如:ReentrantLock,在线程加锁失败时会进行挂起,就是走的park,直至超时或中断)
  1. 多线程

什么是进程?什么是线程?进程与线程的区别?什么是多线程?多线程解决什么问题?多线程可能会引入哪些问题?
参考:https://blog.csdn.net/yaosiming2011/article/details/44280797

  1. 死锁的解决
  2. 同步、异步、阻塞、非阻塞

同步、异步是结果,阻塞、非阻塞是过程。
同步、异步是目的,阻塞、非阻塞是实现方式。
调用同步的方法在没有拿到锁的情况下会出现阻塞,在获得锁的情况下不会出现阻塞。
BIO:blocking IO,阻塞式IO。

  1. NIO的原理
  2. wait\notify

六、数据库

  1. 事务-四要素
  • 原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
  • 一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
  • 隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。
  • 持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库。
  1. 事务隔离级别
  • read-uncommitted,读未提交,导致
  • read-committed,不可重复读
  • repeatable-read,可重复读
  • serializable,串行化
  1. 事务并发问题
  • 脏读:事务A读取到事务B还未提交的新数据,但事务B最后执行失败,回滚了数据,因此事务A读到了错误的脏数据。
  • 不可重复读:事务A多次读取同一数据,由于事务B在更新、修改此数据,导致事务A多次读同一数据出现不同结果。(针对某行记录的修改)
  • 幻读:事务A统计某一条件的所有数据信息,事务B刚创建一条符合条件的数据,在事务A根据相同条件再查询时,发现统计数据又多了一条,好像出现了幻觉。(针对结果集的删除、新增)
  1. 乐观锁、悲观锁,及其实现

  锁是一种方式,并非数据库独有。

  1. MVCC

  多版本并发控制机制
  InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,分别保存了这个行的创建时间和删除时间。这里存储的并不是实际的时间值,而是系统版本号(可以理解为自增ID),其实是CAS(compare and swap)的思想。


六、开源框架

  1. RPC框架
  2. MQ框架
  3. MQ消息重复如何处理
  4. MQ如何保证顺序,是否可以并发消费顺序

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章