美团秋招后端岗AI面试
八股:
1.synchronized和lock有什么区别
synchronized
适合简单的同步场景,而 Lock
提供了更多高级的锁操作和控制能力。
synchronized是内置锁,可以用于方法或代码块。它有多个级别:1无锁。2偏向锁=》没有其他线程竞争时使用,旨在提高没有竞争情况下的同步效率。它通过将锁“偏向”到第一个获取锁的线程来减少同步开销。只有当其他线程试图获取同一个锁时,偏向锁才会撤销并升级到更高级别的锁。偏向锁的核心思想是,如果没有其他线程尝试获取这个锁,那么偏向锁就会继续保持在最初获取锁的线程上。线程获取偏向锁的操作是非常轻量级的,只需要修改锁的标记而不涉及实际的锁操作。3轻量级锁:使用线程级别的锁,自旋并检查锁是否被其他线程持有,这样可以减少线程切换造成的开销。4重量级锁:操作系统级别的互斥锁。线程在获取锁时会被阻塞,直到锁可用时才会被唤醒。
synchronized是非公平的。性能提升,但可能有饥饿现象。它不能响应中断。
java提供了多种lock,包括ReentrantLock,读写锁等。synchronized和ReentrantLock都属于悲观锁。
ReentrantLock只能用于代码块。需要手动加锁和释放锁,不像synchronized,是进入代码块后自动加锁、释放锁的。
ReentrantLock有以下性质。1可重入性:同一线程可以多次获得同一个 ReentrantLock 实例的锁而不会发生死锁,重入的时候holdCount++,只有当count降为0的时候其他线程才有机会获取这个锁。2公平性:ReentrantLock 可以配置为公平锁(即按照请求的顺序来获取锁)或非公平锁(即可能会使后来的线程先获得锁)。3可中断性:可以在锁等待时响应中断,允许线程在等待锁的过程中被中断。设置超时时间:如果长时间等待后还没有拿到锁,可以放弃获取锁。
从底层实现来看:
synchronized是JVM层面通过监视器实现的,比较少涉及底层实现。它的原理是:每个对象在 Java 中都有一个关联的监视器,线程要进入临界区就需要获取对象的监视器。
ReentrantLock是基于AQS实现的。AQS是一个抽象类,提供了同步器的基础框架,帮助你实现各种类型的同步器。AQS 内部维护一个队列,用于管理等待获取锁的线程。当一个线程尝试获取锁失败时,它会被加入到这个队列中,直到锁变得可用。
2.ConcurrentHashMap和HashMap有什么区别
hashmap不是线程安全的。在JDK1.7的时候,采用数组+链表的数据结构,每个数组元素是链表的头节点,链表用来解决哈希冲突的问题。在数组扩容的时候,可能会有两个线程可能会同时扩容 HashMap,造成entry链死循环和数据丢失的问题。
具体来说,扩容时,HashMap 会创建一个新的更大的数组,并将旧数组中的所有元素重新计算哈希位置后转移到新的数组中。如果两个线程同时扩容,一个线程可能已经完成了将某些链表节点转移到新数组,而另一个线程可能在此时也在操作链表节点,最终可能形成一个环形链表。
如果扩容过程中线程同时修改 HashMap,可能会导致某些节点被丢失,导致数据不一致。比如在扩容过程中,某些元素可能没有被正确转移到新数组中。
另外,在执行get的时候,如果别的线程修改或删除了数据,也会出错。
在jdk1.8中,数据结构改成数组+链表+红黑树,但依然存在并发问题。
关于ConcurrentHashMap:它在读操作的时候不需要加锁。主要思想是分段锁。在JDK1.7,每一个HashEntry是一个链表,多个HashEntry组成一个Segment,以Segment为单位加锁。在JDK1.8,锁的粒度更小,不再对整个表加锁,而是对表中的桶(或链表/红黑树)加锁,降低了发生冲突的概率。是通过对每个桶加synchronized实现的。
3.什么是TCP的粘包问题
客户端向服务端发送数据,粘包:服务端收到了两个包,但没有明确界限。拆包:一个大数据包被拆成了两个包 服务端收到了被拆好的包。
本质原因:TCP是面向流的,缓冲区是1024个字节大小,如果应用一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送。如果应用一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是「拆包」。
解决办法:方法1.给包加上头部,在头部加上包的实际长度。方法2.发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。方法3.在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
使用的算法:Nagle。
和UDP的区别:UDP是面向消息传输的,是有保护消息边界的,接收方一次只接受一条独立的信息,所以不存在粘包问题。
举个例子:有三个数据包,大小分别为2k、4k、6k,如果采用UDP发送的话,不管接受方的接收缓存有多大,我们必须要进行至少三次以上的发送才能把数据包发送完,但是使用TCP协议发送的话,我们只需要接受方的接收缓存有12k的大小,就可以一次把这3个数据包全部发送完毕。
4.websocket的select epoll poll等是什么
首先理解IO多路复用,这是一种允许程序同时处理多个 I/O 操作的技术,这样就不需要为每个 I/O 操作都创建一个线程或进程,提高IO操作效率。I/O 多路复用允许程序同时监视多个 I/O 操作(如文件描述符、网络连接等),当某个 I/O 操作准备好进行(例如网络连接上有数据到达),系统会通知程序,程序可以立即处理这些事件,而不必轮询每个 I/O 操作的状态。
select适用于小规模监视,使用 select 函数将多个文件描述符放入一个文件描述符集合中,然后阻塞等待这些文件描述符中的一个或多个变为活动状态。在处理大量文件描述符时会降低,因为它在每次调用时都需要遍历文件描述符集合。此外,select 也有文件描述符数量的限制(通常是 1024)。
poll用于中等规模,使用一个 pollfd 结构数组来代替 select 的文件描述符集合。因为使用动态数组所以不受文件描述符数量的限制(可以处理更多的文件描述符)。
epoll用于大规模,是 Linux 特有的高效 I/O 多路复用机制。通过创建一个内核级的事件表来跟踪活动文件描述符。程序可以通过 epoll_ctl 添加、删除或修改感兴趣的事件。epoll_wait 函数阻塞并返回那些已发生事件的文件描述符。它不需要遍历所有文件描述符。它使用事件驱动的机制,只有在文件描述符实际变为活动状态时才会通知应用程序,避免了无效的轮询。
5.什么是SSH连接 如何进行SSH连接
是一种网络协议,用于通过不安全的网络安全地访问计算机,它提供了加密的通信渠道。使用22端口。可以通过SSH进行登录,执行命令,通过SCP发送文件。
连接方式:
SSH连接的整个过程是这样的:
(1)远程主机收到用户的登录请求,把自己的公钥发给用户。
(2)用户使用这个公钥,将登录密码加密后,发送回来。
(3)远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。
存在一个风险:如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像https协议,SSH协议的公钥是没有证书中心(CA)公证的,也就是说,都是自己签发的。可以设想,如果攻击者插在用户与远程主机之间(比如在公共的wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是中间人攻击。
解决办法:采用非对称加密。生成公钥和私钥,把公钥发给服务端,然后直接通过用户名和地址就能访问服务端
6.linux服务器如何查看CPU硬件使用情况
1.top命令 显示当前CPU的使用情况、各个进程的CPU占用率
2.mpstat -P ALL 1 其中mpstat
命令显示各个CPU核心的使用情况,-P ALL
选项表示显示所有CPU核心的信息,1
表示每秒刷新一次数据
7.java有哪些新增的函数式接口
这指的是接口里仅有一个抽象方法,但是可以有多个非抽象方法
可以使用Lambda表达式来表示该接口的一个实现,例如:
GreetingService greetService1 = message -> System.out.println("Hello " + message);
1.8之前的函数式接口有:Runnable,Callable,Comparator
1.8新增的:java.util.function
例如:BiFunction<T, U, R>
是 JDK 1.8 中引入的函数式接口之一,它表示一个接受两个输入参数(类型为 T
和 U
)并返回一个结果(类型为 R
)的方法
// 定义一个 BiFunction,接受两个 Integer 参数,返回它们的和
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
// 使用 BiFunction
Integer result = add.apply(5, 3);
8.mysql的表级锁 行级锁有什么区别
表级锁在操作时会锁住整个表,因此所有对该表的访问会被阻塞,虽然管理简单,但在高并发情况下可能导致性能瓶颈。行级锁则只锁住表中的特定行,允许其他行的并发访问,从而支持更高的并发性,但管理开销和复杂性较高。通常,表级锁适用于读写操作较少的场景,而行级锁适用于需要频繁并发操作的环境。MyISAM 存储引擎使用表级锁,而 InnoDB 存储引擎使用行级锁。
全局锁可以让整个数据库变为只读状态,用于备份,但会让业务停止。
表级锁分为:表锁,元数据锁MDL(是一种读写锁,用来阻止对表结构的更改),意向锁,AUTO-INC锁
行级锁主要有:记录锁,间隙锁,Next-key Lock
场景题:
- 如何设计用户反馈系统
- 对于反馈系统中不同优先级的反馈 如何处理