阿里面试题

阿里巴巴一面

先介绍一下自己吧

说一下自己的优缺点

具体讲一下之前做过的项目

你觉得项目里给里最大的挑战是什么?

HashMap 了解么吗?说一下 put 方法过程

HashMap是键值对存储数据结构,内部以key-value+链表的形式存储数据,jdk1.8之前,是以Entry创建数据节点,jdk1.8之后以Node创建数据节点。

put方法中要先检查存储数据的数组是否已初始化,计算key的哈希值,若该哈希值所在槽无对象,则直接设置进去;若该槽有值,则校验key值是否相等,若相等则直接替换,并将旧值返回;若key不相等,则校验节点的类型是否为TreeNode,若为TreeNode则走TreeNode的putTreeVal;若为普通Node节点,则迭代该槽上的Node节点,通过当前节点的next属性获取下一节点,若next的key与put的key相等(== && equals),则替换next的value;若next为null,则在此处存储,并且当前节点的next指向新创建的Node对象;最终返回原值或null

HashMap 是不是线程安全?

不是线程安全的,在高并发情况下会出现脏数据的情况

如果想使用线程安全的Map,则可以使用Collections类中的synchronizedMap方法去创建一个Collections内部类SynchronizedMap的实例,该内部类中的方法是使用synchronized关键字实现的线程并发锁;Hashtable类同;或者如果项目使用的是jdk1.5及以上版本的话,可以使用ConcurrentHashMap类,该类是使用了分段锁和CAS的方式实现的并发控制,比synchronized更加灵活高效,分段锁可以实现在写的同时放任其他线程读取非本段的数据,CAS方式则仅仅锁住被操作的节点。

HashMap 为什么不用平衡树?

平衡树在极端情况下会出现非常高的树,在查找的过程中会变慢,而红黑树在插入数据的时候会通过自旋转缩短树的高度

AQS 知道吗?知道哪一些呢?讲一讲。

AQS是AbstractQueuedSynchronizer类的缩写,JUC包中的锁基本实现于AQS,可以实现共享锁和排它锁,AQS是读写锁ReentrantLock的基类,内部通过acquire和acquireShared方法分别实现排它锁和共享锁。

CLH 同步队列是怎么实现非公平和公平的?

CLH队列是通过链表的形式将每一个节点的连接到一起,公平是指在头结点被处理的时候,其他节点都处于wait状态,当处理完之后,将后续所有的节点全部唤醒,所有队列是公平的;即使队列中所有的节点都被唤醒,也不会出现谁先竞争到资源谁执行的情况,永远都是先执行离对列头最近的无中断标志的节点,所以CLH队列又是非公平的。

ReentrantLock 和 synchronized 的区别

两者都是本地锁,都是为了防止并发情况下出现数据错乱的情况,都是可重入锁。ReentrantLock有共享锁和排它锁两种锁机制,而synchronized只能是排它锁,synchronized在jdk1.5之后自带锁升级机制,包括了偏向锁、轻量级锁和重量级锁,但ReentrantLock只是重量级锁。

讲一下 JVM 的内存结构

JVM内存结构分为线程共享内存区和线程私有内存区,线程共享内存区包括方法区/元空间、堆,线程私有内存区包括程序计数器、Java栈、本地方法栈,元空间是在jdk1.8之后用来代替方法区的,可以通过-XX:+MetaspaceSize=10g -XX:+MaxMetaspaceSize=20g来指定元空间的大小,方法区/元空间用于存放类的定义信息、常量等信息,堆用于存放new出来的对象,Java栈和本地方法栈为线程私有主要存储线程中的对象引用和方法调用信息等,程序计数器则为了记录所在线程当前执行的指令位置。

JVM 里 new 对象时,堆会发生抢占吗?你是怎么去设计 JVM 的堆的线程安全的?

不会发生抢占,JVM可以将new出来的对象存在堆上也可以存入线程栈中,也就是通过逃逸分析决定对象是分配到线程共享的堆上还是栈上分配,可以通过-XX:+DoEscapeAnalysis -XX:+EliminateLocks来开启逃逸分析,但是仅在-server模式下有效,可以通过java -version来查看若jre是server版本,则默认就是server模式。JVM堆的线程安全通过使用volatile关键字、ThreadLocal类或者加锁来实现。

讲一下 Redis 的数据结构

Redis内部是以key-value的形式存储数据的,每一个key-value都会以redisObject结构体,结构体中包括数据类型、编码方式、过期策略、引用数量、值结构体实例,值的结构体中包括的key的值,

Redis 缓存同步问题

讲一讲 MySQL 的索引结构

MySQL的索引有B+树和Hash两种结构,在InnoDB存储引擎中,默认支持B+树结构,不支持Hash结构,但是我们可以使用Hash结构,InnoDB通过B+树实现自适应Hash来满足我们使用Hash结构的索引。MySQL之所以选择B+树作为存储结构,是因为其比AVL树高度更可控,比B-树在查询效率上更快。

讲一下 Redis 分布式锁的实现

Redis通过使用setnx+expire或者set key value nx ex time来设置分布式锁,也可以使用lua脚本创建分布式锁。三种方式中,setnx+expire可能会发生异常情况导致锁的key设置过期时间失败,最终锁无法自动释放而影响具体业务处理;分布式锁之所以设置过期时间,是为了防止在创建了锁之后未释放锁而产生的永久锁,这种情况将会导致其他线程永久性的加锁失败。

实际生产环境中,我们一般都是使用Redis集群为应用提供缓存服务,如果在多写的情况下,Master尚未同步到全部Slave之前,会出现同时有多个线程向不同的写服务器发起加锁请求,为了预防这种情况,在加锁的时候,可以向所有的节点同时发起写请求,这样保证了数据的强一致性。

ConcurrentHashMap 如何保证线程安全?

ConcurrentHashMap在jdk1.8之前使用Segment Lock(分段锁)的方式对数据段进行加锁,在该数据段加锁的时候,不会影响其他数据段的数据读写,从而达到提高并发的效率;在jdk1.8之后,使用CAS对具体的某个Node进行加锁,此方法仅仅对线程正在操作的那条数据加锁,不会影响到Map中其他数据的读写。

数据库索引了解吗?讲一下

MySQL索引有主键索引、普通索引两种,又可细分为单索引和复合索引,InnoDB中的索引存储结构默认为B+树,MyIsam中主键索引存储的是数据在磁盘上的位置,InnoDB中主键索引存储的是实际数据,普通索引中存储的是主键数据,所以在使用普通索引查找数据时,是先通过二分法查询到主键值,然后再到主键索引树中根据主键值查询出具体的数据,若是复合索引且所查询的字段均在复合索引中,此类索引查询称为覆盖索引,也就是不需要通过回表查询主键索引树即可返回。

常见排序算法

TCP 三次握手,四次挥手。

TCP在通信时需要先建立连接,为了保证数据发送的稳定性及可靠性,需要进行预通信,也就是我们平时与人见面时的握手礼仪,第一次握手是client端向server端发送一个通知(seq=x,SYN=1),告诉server端我要向你发送数据了,是否做好了接收准备,然后client端状态变为SYN_SENT,server端若已经做好准备,则向client端回应一条消息告诉它我已经做好了准备,可以将数据发送过来了,此为第二次握手(seq=y,SYN=1,ACK=1,ack=x+1),server端状态变为SYN_RECV,client端接收到server端回应的消息后,向server端发送确认包(seq=x+1,ACK=1,ack=y+1),然后client和server端同时变更状态为ESTABLISHED,到此完成三次握手。

在通信结束后需要关闭连接,client端向server端发送断开请求(第一次挥手),server端接收到请求后回应client端,然后server端进入到等待关闭状态(第二次挥手),client接收到回应后向server端发送确认断开请求(第三次挥手),server端收到确认消息后回应client进行断开(第四次挥手),若最后client迟迟未接收到server的确认断开回应,则会重试一次,重试仍然未收到回应则自动断开。

深入问了乐观锁,悲观锁及其实现

悲观锁和乐观锁在读写效率上有很大的区别,悲观锁是在操作数据时,被操作的数据不可被其他线程/连接访问,除非等当前操作的事务提交或释放锁,在MySQL中,可以通过select for update来实现悲观锁;乐观锁在效率上比悲观锁高很多,可以通过版本进行数据控制,比如MySQL中的MVCC。

阿里巴巴二面

自我介绍 + 项目介绍。

你在项目中担任什么样的角色?

那你觉得你比别人的优势在哪里?你用了哪些别人没有的东西吗?

说一下 HashMap 的数据结构

红黑树和 AVL 树有什么区别?

树高度

如何才能得到一个线程安全的 HashMap?

讲一下 JVM 常用垃圾回收器

JVM常用垃圾收集器有CMS、G1,

Redis 分布式锁

再描述一下你之前的项目吧

你觉得这个项目的亮点在哪里呢?

你设计的数据库遵循的范式?

Java 怎么加载类?

linux 常用命令有哪些?

Spring 的 IOC, AOP。

讲一下 ORM 框架 Hibernate

设计模式了解吗?讲一下

自己实现一个二阶段提交,如何设计?

阿里巴巴三面

在项目中,并发量大的情况下,如何才能够保证数据的一致性?

ElasticSearch 为什么检索快,它的底层数据结构是怎么样的?

JVM 内存模型

Netty 应用在哪些中间件和框架中呢?

线程池的参数

讲一下 B 树和 B+ 树的区别

为什么要用 Redis 做缓存?

了解 SpringBoot 吗?那讲一下 SpringBoot 的启动流程吧

如何解决 bean 的循环依赖问题?

Java 有哪些队列?

讲一讲 Spring 和 Springboot 的区别

最近看了什么书?为什么?

你平时是怎么学习 Java 的呢?

wait() 和 sleep() 的区别

原子变量的实现原理

CAS 的问题,讲一下解决方案。

有没有更好的计数器解决策略

讲一讲 NIO 和 BIO 的区别

Nginx 负载均衡时是如何判断某个节点挂掉了?

讲一下 Redis 的数据类型和使用场景

k8s 的储存方式是怎样的?

Spring AOP 原理是什么?怎么使用?什么是切点,什么是切面?最好是举个例子

算法题:给一堆硬币的 array,返回所有的组合

阿里巴巴总监面

算法:给一个 set 打印出所有子集;多线程从多个文件中读入数据,写到同一个文件中;

判断 ip 是否在给定范围内;打乱一副扑克牌,不能用额外空间,证明为什么是随机的。

TCP 和 UDP 区别

线程池的原理以及各种线程池的应用场景

线程池中使用有限的阻塞队列和无限的阻塞队列的区别

如果你发现你的 SQL 语句始终走另一个索引,但是你希望它走你想要的索引,怎么办?

MySQL 执行计划

数据库索引为什么用 B+ 树?

你在做 SQL 优化主要从哪几个方面做,用到哪些方法工具?

有没有想问的?

阿里巴巴 HR 面

自我介绍

平时怎么学习的?

有什么兴趣爱好吗?

怎么看待 996?

怎么平衡工作和学习?

……

有没有什么想问的