拼多多社招 Java一面面经

拼多多社招 Java一面面经
最新回答
心事过重

2021-01-19 22:37:05

拼多多社招Java一面主要围绕操作系统、数据库、并发编程、缓存及高并发高可用设计等核心知识点展开,并包含一道算法编程题。具体面试问题及解答要点如下:

操作系统相关
  • 线程和进程的区别

    资源占用:进程是资源分配的基本单位,拥有独立的内存空间、文件描述符等;线程是CPU调度的基本单位,共享进程的内存空间(如代码段、数据段等),但拥有独立的栈和程序计数器。

    开销:进程创建、销毁和切换的开销较大(需申请/释放资源、更新PCB等);线程开销较小(共享进程资源,切换仅需保存/恢复少量寄存器状态)。

    通信:进程间通信(IPC)需通过管道、消息队列、共享内存等机制;线程间可直接通过共享内存通信,但需同步机制避免数据竞争。

  • 线程和进程在调度时的区别

    调度单位:进程是资源分配单位,线程是CPU调度单位。操作系统调度时,优先调度线程(轻量级),进程内线程共享进程时间片。

    上下文切换:进程切换需保存/恢复完整的进程上下文(内存映射、文件状态等);线程切换仅需保存/恢复线程私有数据(栈、寄存器等),开销更小。

  • 操作系统给线程和进程分配的资源

    进程资源:独立地址空间、全局变量、文件描述符、信号处理、子进程控制权等。

    线程资源:线程栈(存储局部变量、函数调用栈)、程序计数器、寄存器组、线程本地存储(TLS)等。

并发编程相关
  • 线程安全及实现方式

    定义:当多个线程访问共享数据时,若能保证数据在任何时刻的修改都是正确的(如原子性、可见性、有序性),则称线程安全。

    实现方式

    同步机制:使用synchronized关键字、ReentrantLock等互斥锁保证临界区代码的原子性。

    不可变对象:通过final修饰共享变量或使用不可变类(如String)避免修改。

    线程局部存储:使用ThreadLocal为每个线程分配独立变量副本。

    并发容器:使用ConcurrentHashMap、CopyOnWriteArrayList等线程安全集合。

  • 互斥锁的实现原理

    硬件支持:依赖CPU提供的原子指令(如CAS,Compare-And-Swap)或操作系统提供的信号量机制。

    Java实现:synchronized通过JVM的monitorenter和monitorexit指令实现,底层依赖操作系统的互斥锁(如Linux的futex);ReentrantLock通过AbstractQueuedSynchronizer(AQS)框架实现,使用CAS操作和队列管理线程阻塞与唤醒。

  • ReentrantLock的灵活性及实现

    灵活性

    支持公平锁(先到先得)和非公平锁(可插队),通过构造函数参数配置。

    提供tryLock()方法,支持超时或非阻塞获取锁。

    支持可中断锁(lockInterruptibly()),允许线程在等待锁时响应中断。

    实现

    lock():通过CAS操作尝试获取锁,若失败则将线程加入同步队列并阻塞。

    unlock():释放锁并唤醒队列中的后续线程(通过LockSupport.unpark())。

数据库相关
  • MySQL索引的数据结构

    B+树:MySQL默认使用B+树作为索引结构,因其具有以下优势:

    平衡性:所有叶子节点在同一层,保证查询效率稳定(O(log n))。

    范围查询:叶子节点通过指针连接,支持高效的范围扫描。

    高扇出性:非叶子节点仅存储键值,可容纳更多索引项,减少树高度。

  • 多条索引下的查询策略

    索引合并:MySQL可能使用多个单列索引进行合并(如index_merge优化),通过OR或AND条件组合结果。

    最左前缀原则:对于复合索引(如(a, b, c)),查询需从左到右匹配连续列(如a=1 AND b=2可用索引,b=2不可用)。

  • 索引选择性

    定义:索引列中不同值的数量与总记录数的比值(范围0~1),选择性越高(接近1),索引区分度越好,查询效率越高。

    优化:为高选择性列(如用户ID、订单号)创建索引,避免低选择性列(如性别、状态)单独建索引。

缓存相关
  • 缓存雪崩及解决方案

    定义:大量缓存同时失效或缓存服务不可用,导致请求直接打入数据库,引发系统崩溃。

    解决方案

    随机过期时间:为缓存键设置随机过期时间,避免集中失效。

    多级缓存:使用本地缓存(如Caffeine)和分布式缓存(如Redis)分层存储。

    熔断降级:当数据库压力过大时,临时返回降级数据(如默认值或缓存空值)。

  • 替代Redis的缓存方案

    Memcached:纯内存缓存,支持简单键值存储,性能高但缺乏持久化和复杂数据结构。

    Ehcache:Java本地缓存,支持堆内和堆外存储,适合单机场景。

    Tair:阿里开源的分布式缓存,支持持久化和多种数据结构。

  • 防止数据库被打爆的其他方法

    限流:通过令牌桶、漏桶算法限制请求速率(如Guava RateLimiter)。

    队列削峰:使用消息队列(如Kafka、RocketMQ)异步处理请求,平滑流量峰值。

    读写分离:将读请求分流到从库,减轻主库压力。

高并发与高可用
  • 高并发与高可用的区别

    高并发:系统在单位时间内处理大量请求的能力(如QPS、TPS),侧重性能优化(如缓存、异步、无状态设计)。

    高可用:系统在部分组件故障时仍能正常提供服务的能力(如SLA 99.99%),侧重容错设计(如冗余、降级、熔断)。

  • 提升系统高可用的方案

    冗余设计:部署多副本(如主从复制、集群),避免单点故障。

    故障转移:使用负载均衡(如Nginx)或服务发现(如Eureka)自动切换故障节点。

    数据备份:定期备份数据并验证恢复流程(如全量+增量备份)。

算法编程题
  • 判断三点共线

    暴力解法:遍历所有三元组,计算斜率是否相等(时间复杂度O(n3))。

    优化方法

    哈希表存储斜率:固定一个点,计算其他点与该点的斜率,统计相同斜率的数量(需处理垂直斜率情况)。

    向量叉积:对于三点A(x1,y1)、B(x2,y2)、C(x3,y3),若向量AB与AC的叉积为0(即(x2-x1)*(y3-y1) - (y2-y1)*(x3-x1) == 0),则三点共线(时间复杂度O(n2))。