这是一位牛友面试滴滴的题目,本篇文章尝试回答一下,如有错误,欢迎大家留言指正原面经链接:https://www.nowcoder.com/discuss/482240892393226240?sourceSSR=users一面,40min1.Java 有什么集合,说详细一些,每个集合有什么实现类?2.HashMap 和 ConcurrentHashMap 区别 ?    答:HashMap底层是数组+链表存储数据(Java8后链表长度大于一定值,链表会转化为红黑树),当存放键值对(key, value)时,首先对key计算哈希值,来确定键值对在数据中的存放位置,如果不同的key的hash值相同,则会发生哈希冲突,HashMap通过链地址法来解决哈希冲突;当HashMap中的元素数量达到数组大小与加载因子(默认大小0.75)乘积时,HashMap会尽心扩容,扩容会新建一个新的数组,新数组为旧数组大小的2倍(注:扩容涉及到元素的重新分配,相对比较耗费性能);HashMap不是线程安全的,多线程环境下有可能会出现线程安全问题;HashMap中允许null作为键和值ConcurrentHashMap底层也是采用数组+链表/红黑树的结构存储数据,但是它采用了分段锁技术,即将数据分为多个段,每个段独立加锁,当某个线程访问一个段时,不会阻塞其它段的访问,极大的提高的并发访问的效率。在Java8之后,ConcurrentHashMap放弃了段的概念,而是进一步降低了锁的粒度,通过synchronized +CAS来保证线程安全;ConcurrentHashMap与HashMap解决哈希冲突以及扩容的原理均类似;ConcurrentHashMap中null不允许作为键和值3.线程和进程的区别 ?答:根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位内核通过进程表项(PCB)来描述进程,操作系统内核通过一个双向链表来管理PCB,比如进程创建时,将该进程的PCB添加到双向链表中;当进程销毁时,将该进程的PCB从双向链表中删除。每一个进程会有自己独立的虚拟地址空间,也就是说有自己的一个页表,创建进程时,加载器会将可执行文件映射到该虚拟地址空间;当CPU访问虚拟地址,如果页表未命中,也就是说该虚拟页还没有缓存到物理内存中,它就会触发一个缺页异常。进程有自己独立的虚拟地址空间,同时进程切换时,不仅需要切换寄存器、堆栈,还需要进行虚拟地址空间的切换,切换代价比较大;而线程共享进程的地址空间,切换时进需要切换寄存器和栈,切换代价比较小4.多线程了解吗,线程池了解吗?答:多线程的目的是为了最大限度利用CPU资源,通过多线程可以同时执行多个任务,但是线程的频繁创建和销毁会十分浪费性能,于是可以通过线程池来解决这一问题,Java中可以通过new ThreadPoolExecutor()或者Executors.newFixedThreadPool()来创建线程池,线程池有几大核心参数:a. 核心线程数corePoolSize:线程池中始终存在的线程数,即使线程处于空闲状态,也不会被被回收b. 最大线程数maximumPoolSize: 线程池中允许存在的最大线程数c. 工作队列WorkQueue:用于存放待处理任务的阻塞队列d. 线程工厂ThreadFactory: 用于创建新线程的工厂,可以通过这个参数来定义如何创建新线程(比如定义线程的名字等)e. 拒绝策略:当工作队列满了之后,且线程已经达到了线程池最大线程数目,线程池会采用拒绝策略来处理新的任务注:当核心线程无法处理提交的任务时,会暂时将任务存放到任务队列中,如果任务队列已满,则会创建线程(直至最大线程数目),如果已经达到了最大线程限制,提交到线程池的任务依旧在增多,则通过设置的拒绝策略来对后续提交的任务进行处理。5.数据库事务了解吗,索引了解吗答:数据库事务指对数据库的一系列操作,要么全部成功,要么全部不执行。事务需要满足四个基本原则即:ACID原则a. 原子性:事务中的所有操作要么全部成功,要么全部不执行。如果在事务执行过程中出现故障,则会回滚已经执行的操作b.一致性:事务开始之前和事务执行完之后,数据库中的数据需符合预设的规则,保证数据的正确性。比如账户A有400元,账户B有400元,现在账户A向账户B转账200元,那么转账这个操作就是一个事务,这个是事务执行前后,均需要满足账户A+账户B的总金额为800,这便是一致性c.隔离性:数据库运行多个事务同时对数据进行读写和修改,隔离性可以防止多个事务并发执行时而导致的数据不一致,事务隔离主要分为读未提交、读已提交、可重复读、串行化d.持久性:事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失6.聚簇索引和非聚簇索引了解吗?答:在MySQL中通常使用B+树作为索引的存储结构,对于聚簇索引:B+树的非叶子节点中仅存放主键值,而叶子节点中存放主键值和数据,其中叶子节点之间通过双向链表连接,便于范围查询,叶子节点内部的数据通过链表连接,支持二分查找非聚簇索引:与聚簇索引的区别在于叶子节点中不存放数据,而是存储主键值,因此如果要通过非聚簇索引查找数据(非主键),需要先找到主键,然后再去聚簇索引中根据主键查询数据,成为“回表”7.Redis 缓存穿透怎么回事,怎么解决  答:缓存穿透指查询的数据既不在缓存中,也不在数据库中,这样由于在缓存中取不到数据,每次均会去数据库中查询,对数据库造成很大的压力。解决方法:a. 布隆过滤器:使用布隆过滤器可以判断一个数据是否存在,这样如果对于数据库中不存在元素可以直接通过布隆过滤器直接判断,从而避免访问数据库b.缓存空对象:第一次访问时,没有相应的数据,可以直接在redis中缓存一个空结果,这样后续的请求便可以被redis拦截了二面,40min1.Redis 分布式怎么做,知道哨兵吗?答:redis一个集群通常有多个节点组成,这些节点中有的是主节点,而有的是主节点的备份(又称从节点),以此保证主节点挂了之后,依旧有从节点可以代替主节点提供服务(故障转移),其中只有主节点可以接收写命令和读命令,而从节点仅能接收读命令。在redis中考虑到单个节点未必能存储整个数据集合,同时为了进一步提高应对高流量的读写的能力,redis通过“分片”的方式保存数据,即:将整个数据集合分为16384个slot,redis集群中的每个节点拥有其中一部分slot(并且每个slot均有备份),这样redis便打造成了高扩展性高可用的分布式系统了至于哨兵集群主要用来感知Redis的节点是否在线,比如某个主节点突然挂掉,需要按照一定的规则选举某个从节点成为主节点(一般是选举拥有最新数据副本的从节点成为主节点),如果长时间没有主节点,会影响客户端的写入命令执行(毕竟redis中只有主节点可以接收写命令)https://mp.weixin.qq.com/s?__biz=MzIxMzg5ODIxMA==&mid=2247483763&idx=1&sn=949177d06b56d73c3d3bb70bcc0cae2d&chksm=97ae87fea0d90ee89d3a0b9322979838bfb3a045d2e5fcbf0ce85ba783cc28ace3aae6441e03&token=880968211&lang=zh_CN#rd2.线程和进程的区别 ?见上述回答3.线程之间怎么共享资源(我说的是 volatile 修饰变量)答:个人感觉这里应该是回答如何进行线程同步吧或者说线程之间共享资源,如何保证线程安全性a.Synchronized关键字:可以用于修饰变量和代码块,保证同一时刻仅有一个线程可以获取锁并执行同步代码b.Lock锁:java并发库中提供了更加灵活的锁机制,如ReentantLockc.ThreadLocal:ThreadLoacal变量为每个线程创建一个副本,每个线程只能访问自己的副本,从而避免了线程安全问题d.使用并发容器:Java并发库提供了一些线程安全的容器,比如ConcurrentHashMap、CopyOnWriteArrayList等4.ThreadLocal 了解吗,怎么修改和获取数据,底层原理看过吗?答:ThreadLocal主要通过set(), get()方法来设置,获取数据ThreadLocal<String> threadLocal = new ThreadLocal<>();thradLocal.set("hello, world");String value = threadLocal.get();在讨论ThreadLocal 之前,我们需要明白Thread类中有个ThreadLocalMap变量,键值为ThreadLocal类,值为真正的局部变量。ThreadLocal的底层是一个哈希映射,即ThreadLocal.ThreadLocalMap5.数据库索引了解吗答:数据库索引是数据库用于提高查询速度的数据结构,可以把它类比成一本书的目录。索引主要分为主键索引,唯一索引,联合索引,普通索引等,从实现结构上又可以分为B-Tree索引,B+Tree索引、Hash索引等。切记虽然索引可以提高查询速度,但是索引也占据存储空间,所以要合理的设计索引。6.数据库分库分表了解吗,只分库不分表可以吗,只分表不分库可以吗(没回答出来)答:数据库的分库分表是为了解决单一数据库无法承受过大的数据量以及访问压力,通过将数据分散到多个数据库或者表中,提高系统额扩展性和性能。只分库不分表可以,即将数据分散到多个数据库中,但每个数据库的表结构均相同,可以有效的分散数据库的访问压力。只分表不分库也可以,即将一个大表的数据分散到多个小表中,但是所有的表均在一个数据库中,可以减少单表数据量,提高查询速度。两种方式各有优缺点,只分库不分表,解决单一数据库压力过大的问题,但是如果表的数据量过大,依旧影响查询效率只分表不分库,可以解决单表数据量过大的问题,但是如果数据库访问压力大,那么性能依旧会受到影响。8.限流了解吗(不了解,面试官给我说这个很常用,而且解决方案很成熟,让我了解一下)答:限流主要用于保护系统在高流量下的稳定性,当系统达到一定阈值时,限流策略就会生效,超过限制的请求将会被拒绝,防止系统因为过载而崩溃。谷歌有非常成熟的限流方案,GuavaRateLimiter,基于令牌桶算法实现,内置两种模式应对不同的限流场景,分别是突发模式和预热模式。核心算法便是令牌桶,桶内令牌的数量以固定的速度增长,每个请求都需要从令牌桶中获取令牌才能被放行,否则就会被拒绝,这样只需要设定令牌生成的速度,便能控制限流阈值。
点赞 1
评论 0
全部评论

相关推荐

06-19 19:06
门头沟学院 Java
码农索隆:别去东软,真学不到东西,真事
点赞 评论 收藏
分享
Java大菜狗:纯纯招黑奴,一天还不到两百那么多要求,还不迟到早退,以为啥啊,给一点工资做一堆活,还以不拖欠员工工资为荣,这是什么值得骄傲的事情吗,纯纯***公司
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务