蚂蚁金服 电话一面

蚂蚁金服 电话一面

面向对象 vs 面向过程?
封装、继承、多态?
常用的设计模式?
重载和重写的区别?
Java 的反射机制?
常用的集合类有哪些?
HashMap 是不是线程安全的?
哪些哈希集合是线程安全的?
推荐使用哪一个?为什么?
进程和线程的区别?
死锁?死锁的四个条件和解决方法?
悲观锁?乐观锁?应用场景?
数据库的索引设计你了解吗?
索引是不是越多越好?太多有什么缺点?
数据库的四种事务隔离机制?
读写分离?
如何解决读写分离的延迟问题?
分库分表了解吗?用过吗?什么时候才用?
缓存击穿?缓存穿透?缓存雪崩?

面向对象 vs 面向过程

  • 面向过程:是一种以过程为中心的编程范式,强调的是功能行为,主要的思考方式是如何通过一步一步的过程来完成任务。它将程序分解为一系列的过程或步骤,每个步骤完成特定的功能。面向过程的典型代表是C语言,程序员需要自己管理程序的流程和数据。
  • 面向对象:是一种以对象为中心的编程范式,强调的是把构成程序的各个部分封装成对象,每个对象都包含数据和对数据进行操作的方法。它将现实世界中的实体建模为对象,通过对象之间的交互来完成任务。面向对象的典型代表是Java、C++等语言,它们支持封装、继承和多态等特性,使得代码更加模块化、可复用和易于维护。

封装、继承、多态

  • 封装:是将数据和操作数据的方法绑定在一起,形成一个独立的对象,并且将对象的内部实现细节隐藏起来,只暴露对外的接口。这样可以保护对象的内部状态不被外界直接访问和修改,提高数据的安全性和代码的可维护性。
  • 继承:是一种机制,允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以重用父类的代码,也可以添加新的属性和方法或覆盖父类的方法。继承有助于建立类之间的层次关系,实现代码的复用和扩展。
  • 多态:是指同一个接口或方法在不同的对象上可以表现出不同的行为。在运行时,根据对象的实际类型来决定调用哪个方法。多态使得程序具有更好的灵活性和可扩展性,可以编写更通用的代码。

常用的设计模式

  • 单例模式:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
  • 工厂模式:定义一个创建对象的接口,但由子类决定要实例化的类。
  • 观察者模式:对象之间定义了一一对多的依赖,当一个对象改变状态时,所有依赖它的对象都会得到通知并自动更新。
  • 策略模式:定义一系列算法,把它们封装起来,并且使它们可以互相替换。
  • 装饰模式:动态地给对象添加一些额外的职责,即增加其功能。

重载和重写的区别

  • 重载(Overloading):是在同一个类中,方法名相同但参数列表不同的多个方法。参数列表不同可以是参数个数不同,或者参数类型不同。重载的方法可以在同一个类中实现不同的功能,调用时根据传入的参数类型和个数来决定使用哪个方法。
  • 重写(Overriding):也称为覆盖,是指子类重新定义父类的方法。子类可以提供与父类方法相同的签名,但实现不同。重写的方法在运行时根据对象的实际类型来决定调用父类的方法还是子类的方法,从而实现多态。

Java 的反射机制

  • 反射机制:是Java提供的一种动态获取类信息和操作对象的机制。它允许程序在运行时访问、检测和修改它本身的类和对象的信息,以及动态地创建对象、调用方法和访问字段等。反射机制主要通过java.lang.reflect包中的类来实现,如ClassMethodField等。

常用的集合类有哪些

  • List:是一个有序的集合,可以包含重复的元素。常见的实现类有ArrayListLinkedListVector等。ArrayList是基于动态数组实现的,访问元素速度快,但插入和删除元素较慢;LinkedList是基于双向链表实现的,插入和删除元素速度快,但访问元素较慢。
  • Set:是一个不允许包含重复元素的集合。常见的实现类有HashSetTreeSetLinkedHashSet等。HashSet基于哈希表实现,添加、删除和查找元素的速度较快;TreeSet基于红黑树实现,可以对元素进行排序;LinkedHashSet则按照元素的插入顺序维护元素的有序性。
  • Map:是一个存储键值对的集合,每个键对应一个值。常见的实现类有HashMapTreeMapLinkedHashMapHashtable等。HashMap基于哈希表实现,提供了较快的插入、删除和查找操作;TreeMap基于红黑树实现,可以按照键的自然顺序或指定的比较器对键值对进行排序;LinkedHashMap则按照插入顺序或访问顺序维护键值对的有序性;Hashtable是线程安全的,但性能相对较低。

HashMap 是不是线程安全的

  • HashMap:不是线程安全的。在多线程环境下,多个线程同时对HashMap进行写操作时,可能会导致数据不一致、死锁或其他异常情况。因为HashMap在进行插入、删除等操作时,并没有对内部结构进行同步保护,多个线程的操作可能会干扰彼此,破坏HashMap的内部结构。

哪些哈希集合是线程安全的

  • Hashtable:是线程安全的,它对方法进行了同步处理,使得在任何时候只有一个线程可以访问其方法。但Hashtable的性能相对较低,因为每次操作都需要获取整个对象的锁。
  • Collections.synchronizedMap():是通过Collections工具类提供的静态方法,可以将一个普通的Map包装成线程安全的Map。它在每次操作时都会对Map进行同步,但同样存在性能问题。
  • ConcurrentHashMap:是Java 5中引入的线程安全的哈希表实现,它采用了分段锁的技术,将哈希表分割成多个段,每个段都有自己的锁。这样在多线程环境下,多个线程可以同时操作不同的段,提高了并发性能。

推荐使用哪一个?为什么

  • ConcurrentHashMap:在大多数情况下推荐使用ConcurrentHashMap。因为它在保证线程安全的同时,提供了比Hashtable和Collections.synchronizedMap()更高的并发性能。它通过分段锁的机制,减少了锁的粒度,使得多个线程可以同时访问不同的段,从而提高了吞吐量。而Hashtable和Collections.synchronizedMap()在高并发场景下,由于每次操作都需要获取整个对象的锁,会导致性能瓶颈。

进程和线程的区别

  • 进程:是操作系统中独立运行的基本单位,每个进程都有自己的独立内存空间、代码段、数据段、堆栈等资源。进程之间的切换开销较大,因为需要保存和恢复各自的上下文环境。进程之间通信相对复杂,通常需要通过文件、套接字等方式进行。
  • 线程:是进程中的一个执行单元,多个线程共享所属进程的内存空间和资源。线程之间的切换开销较小,因为它们共享大部分的上下文环境。线程之间通信相对简单,可以直接访问共享的变量和数据结构。

死锁?死锁的四个条件和解决方法

  • 死锁:是指两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
  • 死锁的四个条件
    • 互斥条件:资源不能被同时共享,即一个资源只能被一个线程占用。
    • 请求与保持条件:线程已经占有了至少一个资源,但又提出了新的资源请求,而该资源已被其他线程占有,此时请求线程被阻塞,但对自己已获得的资源保持不放。
    • 不剥夺条件:线程已获得的资源在未使用完之前,不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
    • 循环等待条件:存在一种线程资源的循环等待链,链中的每一个线程已获得的资源同时被链中的下一个线程所请求,而下一个线程已获得的资源又被再下一个线程所请求,以此类推,最后链中的最后一个线程又在等待第一个线程所占有的资源。
  • 解决死锁的方法
    • 预防死锁:破坏死锁发生的四个必要条件之一。例如,通过资源有序分配策略破坏循环等待条件,或者通过允许资源剥夺来破坏不剥夺条件等。
    • 避免死锁:在资源分配之前,先进行安全检查,确保资源分配后系统仍处于安全状态,不会导致死锁。这需要采用一定的算法,如银行家算法。
    • 检测并恢复:允许死锁发生,但通过定期检测系统状态来判断是否发生死锁,一旦发生死锁,则采取措施进行恢复,如撤销某些线程、剥夺资源等。

悲观锁?乐观锁?应用场景?

  • 悲观锁:是一种假设数据冲突很常见的锁机制。在操作数据时,会先获取锁,确保在操作过程中数据不会被其他线程修改。它适用于数据更新较为频繁、冲突可能性较高的场景,如银行账户余额更新、库存管理等。
  • 乐观锁:是一种假设数据冲突不常见的锁机制。在操作数据时,不使用锁,而是在提交更新时检查数据是否被其他线程修改过。如果未被修改,则提交成功;如果被修改,则提交失败,需要重新尝试。它适用于读多写少的场景,如新闻资讯类网站的内容展示等。

数据库的索引设计你了解吗

  • 索引设计:是数据库优化的重要手段之一。通过在数据库表的列上创建索引,可以加快数据的检索速度,提高查询效率。常见的索引类型有单列索引、复合索引、唯一索引、全文索引等。设计索引时需要考虑查询的频率、数据的分布、索引的维护成本等因素。

索引是不是越多越好?太多有什么缺点

  • 索引不是越多越好。虽然索引可以提高查询速度,但也会带来一些缺点:
    • 增加存储空间:每个索引都需要占用一定的存储空间,过多的索引会增加数据库的存储开销。
    • 降低插入、更新和删除的性能:在进行插入、更新和删除操作时,数据库需要同时维护索引,过多的索引会导致这些操作的性能下降。
    • 增加维护复杂度:过多的索引需要更多的维护工作,如重建索引、更新统计信息等。

数据库的四种事务隔离机制

  • 读未提交(Read Uncommitted):允许一个事务读取另一个事务尚未提交的数据。这种隔离级别可能会导致脏读、不可重复读和幻读等问题。
  • 读已提交(Read Committed):确保一个事务只能读取另一个事务已经提交的数据。它避免了脏读,但仍然可能出现不可重复读和幻读。
  • 可重复读(Repeatable Read):确保同一个事务多次读取同一数据时结果一致。它避免了脏读和不可重复读,但可能会出现幻读。
  • 串行化(Serializable):这是最高的隔离级别,确保事务完全串行执行。它避免了脏读、不可重复读和幻读,但会大大降低数据库的并发性能。

读写分离?

  • 读写分离:是一种数据库架构策略,将数据库的读操作和写操作分开到不同的服务器上。通常,主数据库负责处理写操作,而从数据库负责处理读操作。这样可以分散主数据库的读写压力,提高系统的并发性能和可用性。

如何解决读写分离的延迟问题

  • 数据同步优化:确保主从数据库之间的数据同步及时、准确,减少延迟。可以通过优化复制通道、调整同步参数等方式来提高同步效率。
  • 应用层缓存:在应用层引入缓存机制,对于一些实时性要求不高的数据,优先从缓存中获取,减少对从数据库的依赖。
  • 最终一致性策略:在应用设计时,接受一定程度的数据不一致,采用最终一致性的策略,在数据延迟的情况下,通过重试、补偿等机制来保证数据最终的一致性。

分库分表了解吗?用过吗?什么时候才用

  • 分库分表:是将一个大型的数据库或表分割成多个小的数据库或表,分布在不同的服务器或存储设备上。这样可以解决单库单表在数据量过大时的性能瓶颈问题,提高系统的扩展性和并发性能。
  • 使用场景:当数据库的表数据量达到一定规模,如数千万条以上,导致查询和写入性能下降时;或者当数据库的连接数过多,单台数据库服务器无法承受时,可以考虑进行分库分表。

缓存击穿?缓存穿透?缓存雪崩?

  • 缓存击穿:是指缓存中某个热点数据过期后,大量请求同时访问该数据,导致这些请求同时落到数据库,造成数据库压力骤增,可能引发数据库崩溃。
  • 缓存穿透:是指查询的数据在数据库中不存在,导致每次请求都直接穿透到数据库,无法利用缓存,造成数据库的负担。
  • 缓存雪崩:是指缓存中的大量数据在同一时间过期,导致大量请求同时访问数据库,造成数据库压力过大,可能引发雪崩效应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值