Java面试一

moonjerx
2024-11-11 / 0 评论 / 10 阅读 / 正在检测是否收录...

面试概况

本次面试为快手商业化部门日常实习生的一轮面试,面试时长约为40分钟。面试内容主要集中在Java基础知识、数据库、并发编程、算法等方面。以下是详细的面试问题及回答整理。

面试问题及回答

1. Java 的集合类知道哪些?

Java 的集合类主要分为以下几类:

  • List:有序集合,允许重复元素。常见实现类有 ArrayListLinkedListVector
  • Set:不允许重复元素的集合。常见实现类有 HashSetLinkedHashSetTreeSet
  • Map:键值对集合,键唯一但值可以重复。常见实现类有 HashMapLinkedHashMapTreeMapHashtableConcurrentHashMap
  • Queue:队列集合,支持 FIFO(先进先出)操作。常见实现类有 LinkedListPriorityQueueArrayDeque

2. 说说 HashMap?

HashMap 是 Java 中常用的集合类,基于哈希表实现,允许存储键值对。其主要特点如下:

  • 无序存储HashMap 不保证元素的顺序。
  • 允许空键和空值:但最多只能有一个空键。
  • 线程不安全:在多线程环境下使用 HashMap 可能会导致数据不一致。
  • 时间复杂度:插入、删除、查找操作的时间复杂度均为 O(1)(理想情况下)。

3. HashMap 线程安全吗,如何变线程安全?

HashMap 本身是线程不安全的。可以通过以下几种方式使其线程安全:

  • 使用 Collections.synchronizedMap:将 HashMap 包装成线程安全的 Map

    Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
  • 使用 ConcurrentHashMapConcurrentHashMap 是线程安全的 Map 实现,性能优于 Hashtable

    Map<String, String> map = new ConcurrentHashMap<>();
  • 手动同步:在访问 HashMap 的地方手动加锁。

    synchronized (map) {
        map.put(key, value);
    }

4. ConcurrentHashMap 如何实现的?

ConcurrentHashMap 通过分段锁(Segment)机制实现线程安全。具体实现如下:

  • 分段锁:将整个哈希表分成多个段(Segment),每个段内部是一个小的哈希表。
  • 锁粒度:每次操作只锁定当前段,而不是整个哈希表,提高了并发性能。
  • JDK 1.8 改进:取消了 Segment,改为使用 CAS 操作和锁竞争机制,进一步提高了性能。

5. synchronized 原理以及升级过程

synchronized 是 Java 中的内置锁,用于实现线程同步。其原理如下:

  • 锁的状态:锁有四种状态,依次是无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。
  • 锁升级:锁可以从较低状态升级到较高状态,但不能降级。

    • 无锁状态:没有任何线程持有锁。
    • 偏向锁:偏向于第一个获取锁的线程,减少锁的竞争。
    • 轻量级锁:使用 CAS 操作尝试获取锁,如果失败则升级为重量级锁。
    • 重量级锁:使用操作系统互斥量实现,性能较差。

6. 线程池的参数?

ThreadPoolExecutor 是 Java 中创建线程池的类,其构造方法参数如下:

  • corePoolSize:核心线程数。
  • maximumPoolSize:最大线程数。
  • keepAliveTime:线程空闲时间。
  • unitkeepAliveTime 的时间单位。
  • workQueue:任务队列,用于存储等待执行的任务。
  • threadFactory:线程工厂,用于创建线程。
  • handler:拒绝策略,当任务队列满且线程数达到最大值时的处理策略。

7. full gc, minor gc?

  • Minor GC:回收年轻代(Young Generation)的垃圾收集操作。当年轻代空间不足时触发。
  • Full GC:回收整个堆(包括年轻代和老年代)的垃圾收集操作。通常在以下情况下触发:

    • 老年代空间不足。
    • 系统显式调用 System.gc()
    • Minor GC 时发现老年代空间不足。

8. 垃圾回收算法?

常见的垃圾回收算法有:

  • 标记-清除:标记所有需要回收的对象,然后清除这些对象。
  • 标记-整理:标记所有需要回收的对象,然后将存活对象移动到一端,清除边界外的对象。
  • 复制:将内存分为两个区域,每次只使用其中一个区域,将存活对象复制到另一个区域。
  • 分代收集:将内存分为年轻代和老年代,分别使用不同的回收算法。

9. CPU 密集型和 IO 密集型下如何设置核心线程数?

  • CPU 密集型:任务主要消耗 CPU 资源,核心线程数一般设置为 CPU 核心数 + 1

    int corePoolSize = Runtime.getRuntime().availableProcessors() + 1;
  • IO 密集型:任务主要消耗 I/O 资源,核心线程数一般设置为 CPU 核心数 * 2

    int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;

10. 聚簇索引和非聚簇索引区别

  • 聚簇索引

    • 数据行的物理存储顺序与索引顺序一致。
    • 一个表只能有一个聚簇索引。
    • 查询速度快,但插入、删除、更新操作较慢。
  • 非聚簇索引

    • 数据行的物理存储顺序与索引顺序无关。
    • 一个表可以有多个非聚簇索引。
    • 查询速度相对较慢,但插入、删除、更新操作较快。

11. MySQL 的各个隔离级别,以及分别解决了什么问题

MySQL 的事务隔离级别有四种:

  • 读未提交(Read Uncommitted):最低隔离级别,允许脏读。
  • 读已提交(Read Committed):允许不可重复读,但不允许脏读。
  • 可重复读(Repeatable Read):默认隔离级别,允许幻读,但不允许脏读和不可重复读。
  • 串行化(Serializable):最高隔离级别,不允许脏读、不可重复读和幻读。

12. Redis 有什么数据类型

Redis 支持多种数据类型:

  • 字符串(String):最基本的类型,可以存储字符串、数字等。
  • 列表(List):有序集合,支持从两端插入和删除操作。
  • 集合(Set):无序集合,不允许重复元素。
  • 有序集合(Sorted Set):有序集合,每个元素关联一个分数。
  • 哈希表(Hash):键值对集合,键唯一。
  • 位图(Bitmap):用于处理位级别的操作。
  • HyperLogLog:用于估算集合的基数。

13. Redis 分布式锁实现?

Redis 分布式锁可以通过以下几种方式实现:

  • SETNX 命令:使用 SETNX 命令尝试获取锁。

    SETNX key value
  • EXPIRE 命令:设置锁的超时时间,防止死锁。

    EXPIRE key seconds
  • Lua 脚本:使用 Lua 脚本保证原子性。

    local key = KEYS[1]
    local value = ARGV[1]
    local expire = tonumber(ARGV[2])
    
    if redis.call("setnx", key, value) == 1 then
        redis.call("expire", key, expire)
        return 1
    else
        return 0
    end

14. 项目中的前缀树,自定义注解限频,网站优化过程

  • 前缀树(Trie):用于快速查找字符串,常用于搜索引擎、拼写检查等。
  • 自定义注解限频:通过自定义注解和 AOP 切面实现接口限流。

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface RateLimit {
        int limit() default 100;
        int time() default 1;
    }
    
    @Aspect
    @Component
    public class RateLimitAspect {
        @Around("@annotation(rateLimit)")
        public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
            // 限流逻辑
            return joinPoint.proceed();
        }
    }
  • 网站优化过程

    • 前端优化:使用 CDN、压缩资源、合并文件、懒加载等。
    • 后端优化:优化数据库查询、使用缓存、减少网络请求等。
    • 服务器优化:调整 JVM 参数、优化网络配置、使用负载均衡等。

15. 算法:反转链表

反转链表的实现如下:

public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode current = head;
    while (current != null) {
        ListNode next = current.next;
        current.next = prev;
        prev = current;
        current = next;
    }
    return prev;
}

总结

本次面试涉及的知识点较为广泛,涵盖了 Java 基础、并发编程、数据库、算法等多个方面。准备面试时,建议重点复习这些知识点,并结合实际项目经验进行准备。希望这篇博客对大家有所帮助!

0

评论 (0)

取消

您的IP: