Java中级面试题

1.假如有两个线程共同操作数据库,以乐观锁的角度考虑,怎么确保不会发生并发问题?

PS:考点是CAS,比较并替换。CAS中有三个值,内存中的值,新值,旧值。

假如内存中的值是2000,要进行--操作,A,B两个线程分别从主内存中拉去数据,当A线程进行--操作,新值变成了1999,旧值与主内存中的值一致,将新值替换掉主内存中的值,此时主内存值为1999。当B线程进行--操作,新值也是1999,比较主内存值1999与旧值2000不一致,拉去主内存值,在--,此时旧值变成了1999,新值变成了1998……

依次类推,AB线程共同操作共享资源,数据也不会出现并发问题。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbWVldGJldHRlcmhj,size_20,color_FFFFFF,t_70,g_se,x_16

2.synchronized的原理 

在JDK1.6以前,sync是重量级锁。

重量级锁有一个等待队列,想要抢占锁的线程都进入等待队列中,当线程A获得到共享资源,其他线程进入阻塞状态,当线程A释放锁时,其他线程被唤醒。

这个过程很消耗操作系统,因此sync的效率很低。

在JDK1.6之后,sync应用了锁升级。

起初是无状态的,jvm启动4s后开启偏向锁,当某个线程来竞争,要判断当前锁是否可重新偏向,如果不能,就升级为轻量级锁,当自璇(线程一直尝试获得锁)无法获取到锁,就会升级为重量级锁。

3.Redis缓存击穿、穿透、雪崩

击穿:数据库中有,缓存中没有的数据。

解决办法:

  • 设置热点数据永不过期
  • 加互斥锁

穿透:缓存和数据库中都没有的数据。

解决办法:

  • 将value的值赋为null
  • 在接口层增加校验
  • 布隆过滤器:快速检索一个元素是否在集合中,不存在的一定能检索到

雪崩:同一时间大量数据请求数据库,导致数据库压力大而宕机。

解决办法:

  • 过期时间设置随机,避免同一时间多个缓存同时过期
  • 设置热点数据永不过期
  • 使用锁或队列的方式保证不会有大量线程对数据库一次性进行读写

4.Redis过期键的删除策论有哪些?

定时删除

通过使用定时器来删除,保证过期键尽可能的删除,并释放过期键占用的内存。

对内存友好,对CPU不友好。

惰性删除

获取键时对键进行过期检测,不会在删除其他无关过期键花费CPU

对CPU友好,对内存不友好

定期删除

定时删除和惰性删除的一种折中策略,每隔一段时间执行一次删除过期键操作

5.Redis有哪些数据结构

Sting  List  Hash  Set  Sorted Set

6.为什么Redis最常用的数据类型是String

因为String类型的数据结构简单,存储空间占据小。我们知道redis缓存中的数据是要存到内存中的,而内存的空间毕竟有有限的,所以能用String时,尽量用String

7.Redis的持久化方式

Redis的持久化方式有2种,RDB和AOF

RDB是快照文件的形式将数据持久化,BESAVE命令fork子进程生成RDB文件。

AOF是把所有的写命令记录到日志中,重跑日志文件就能还原数据。

8.Redis的集群模式

为了redis的高可用,现在都会给redis做备份,多启动一台redis,形成主从架构。

主服务器将数据复制到从服务器,有2种方式,完全重同步和部分重同步,如果是第一次会完全重同步,如果是网络中断等会部分重同步。

复制的流程:

  1. 从服务器给主服务发起复制数据请求
  2. 主服务器将RDB文件发给从服务器
  3. 从服务器拿到文件后,先清空自己,再加载RDB文件
  4. 主服务会把发送文件后,修改的命令用buffer记录,从服务器加载完RDB之后,将buffer发送到从服务器

这样就保证了主从服务器的数据最终一致性。

9.Redis的实战场景

  1. 短信验证码
  2. 接口幂等
  3. 统计次数
  4. 分布式锁
  5. 缓存数据

10.线程池的原理

线程池顾名思义就是存放线程的池子,用的时候从里边拿,不用的时候放入池中,避免了多次创建与销毁线程。

线程池中有几个重要的参数:核心线程数、最大线程数、线程等待时间、阻塞队列、拒绝策略。

线程池初始化的时候,线程池中的默认线程数是0,当有任务第一次访问的时候,开始创建线程到核心线程数,如果接着有任务,线程都被占用,那么任务会放入阻塞队列,如果阻塞队列塞满,那么会看核心线程数是否小于最大线程数,如果是,那么接着创建线程来执行任务,当核心线程数=最大线程数且所有线程都占用且阻塞队列塞满,会触发拒绝策略。

11.  三种线程池的适用场景

fixedThreadPool:固定数量线程,核心线程数=最大线程数,阻塞队列是int最大值

适用于cpu计算密集的情况(cpu是调度线程的,cpu密集可以理解为程序一直在计算),因为cpu密集,再去创建线程已经顾不上了,所以固定数量的就足够了。

cachedThreadPool:可扩容数量线程池,核心线程数0,最大线程数为int的最大值,用到多少线程,创建多少。阻塞队列是0

适用于io密集的场景,io密集就会产生io阻塞,那么这是cpu就有空闲,这是就可以创建线程,以保证cpu尽可能多的使用。

singleThreadExecutor:核心线程数=最大线程数=1   单个线程,但是有阻塞队列

12. 在开发中,如何保证线程安全的

①使用线程安全的集合(CopyOnWriteArrayList),Map(CurrentHashMap),原子类(Atomic)

②一次可以使用多少个线程,可以考虑CountDownLatch

③使用synchronized或者Lock进行加锁出来

CopyOnWriteArrayList的底层是基于数组的,每次修改都会复制出来一个数组,在这个新数组上修改,修改不影响读,修改好之后将原数组替换,实现了“读写分离”。

CurrentHashMap的底层是sync+CAS+红黑树,首先CurrentHashMap是基于HashMap的,HashMap是数组+链表的形式,通过key的hashcode方法计算出hashcode值,来判断在哪个位置,如果这个位置有值了,就会调用equals方法,如果值相等替换,如果不等就追加到链表后。

CurrentHashMap增加了同步的操作,利用CAS+Synchronized保证线程安全

13. 模拟一个场景,现在有50个任务,要等这50个任务执行完,再执行下一个方法,怎么设计?

首先,处理50个任务肯定要用到多线程。

可以利用CountDownLatch和线程池结合处理。CountDownLatch是基于AQS的,会将创建CountDownLatch的入参传递给state,countDown()就是利用CAS将state-1,await()是让头结点等待state=0时,释放所有的线程

14. 接口权限控制

首次登录的时候会生成一个token,前端拿到token放到请求头中,以后每次的请求都需要携带token,后端判断前端带过来的与数据库或者缓存中的token是否一致,一致的话代表登录过了。

我们利用spring的aop在每个接口前建一个切面,切面统一执行判断token,记得过滤掉登录接口。

15.RocketMQ如何保证保证消息不丢失?

从3个层面保证消息不丢失

首先是生产者,生产者利用同步刷盘和定时任务补偿来 保证消息不丢失。同步刷盘即生产者发送消息到mq,mq会把消息写入磁盘,再返回结果。如果消息发送失败,会由定时任务重新拉取发送。

比如短信平台是利用mq的重发机制,失败了再重发一次,如果再失败,写入重发表,等待定时任务的扫描,根据规则来重发。

其次是mq,mq要保证集群高可用,然后利用同步刷盘+异步复制的方式,这种方式既能保证消息的可靠性,又能避免性能降低。异步复制是指从主节点复制数据到从节点是异步的,不会阻塞整个流程。

最后是消费者,可以利用rocketMQ的重试机制,默认重复16次,当消息消费失败,返回related消息会自动重试,如果16次都失败就需要补偿机制,补偿机制根据业务情况而定。

16.HTTP和MQ的区别

MQ主要用于异步通信,HTTP是基于请求/响应的

MQ是长链接,HTTP每次需要重新建立链接

MQ的速度比http快

17.mq和http的优缺点

mq异步通信,解耦好;但是增加了系统复杂度,不能保证消息的完全不丢失和顺序

http简单易用,成熟稳定;但它是同步通信,阻塞

18.如何保证MQ的顺序

首先发消息的时候,需要保证顺序的消息要发到同一个mq队列里,因为一个队列只能被一个消费者消费,其次,消费者不能并发消费。

如何保证消息发到同一个队列呢?rocketmq有自带的消息队列选择器,在发送消息的时候实现这个组件,重写方法,在方法里可以写自己的逻辑,比如用消息的流水号的哈希值对队列数取余,就跟分表的逻辑是一样的,短信平台不需要保证消息的顺序性,但是有些业务需要,比如订单业务,创建订单,下单,支付 这几步的操作不能乱,所以这个时候可以用订单号的哈希值对消息队列的队列数取余,选择性发到一个队列中,这样就能保证顺序性

19.有过JVM调优吗?

没有,不过我们一般系统优化的思路是这样的:首先会看数据库方面,看看索引是否合理,然后我们会看代码层面,比如某个接口相应时间长,会看看有没有慢sql、多层循环,看是否还有优化空间,最后会考虑扩容,不过扩容也是运维来做。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值