跳转至

Java 系统知识

2317 个字 预计阅读时间 8 分钟

Abstract

准备面试时稍微学习的一些零散知识

(不用 java,也不喜欢 java,但还是记录一下吧

线性池

  • 线性池的原因
    • 不断的创建和删线程,会带来较大的系统资源负载
    • 线程缺乏统一的管理,可能会带来无限制的创建线程
    • 线程之间抢占资源
  • 线程池的属性
    • 核心线程数:保持存在的线程数量,这些线程会一直存在,不会被删除
    • 任务缓冲锐裂:当所有的核心线程都在运行时,新的任务会被加入到缓冲队列中
    • 非核心线程数:当任务缓冲队列满后,将会创建新的线程来执行队列中的任务,且额外创建的线程数不会超过非核心线程数
    • 空闲线程的存活时间:当非核心线程空闲时,且持续了一段时间后,此线程将会被删除
    • 拒绝策略,当非核心线程和任务缓存队列满后,对待新的任务的策略
  • Java 默认的线程池类型
名称 核心线程数 线程池大小 非核心线程存活时间 等待队列大小
CachedThreadPool 0 60s 0
SingleThreadExecutor 1 1 0
FixedThreadPool n n 0
ScheduledThreadPoolExecutor
  • Java 默认的线程池有什么问题,为什么会引起 OOM 异常(OutOfMemoryError)
    • CachedThreadPool 允许创建无线的线程,从而引起 OOM 异常
    • SingleThreadExecutor FixedThreadPool 请求队列为无限长,可能会堆积大量的消息,从而引发 OOM 异常。

Java 内存

  • 内存类型
    • 主内存:线程之间共享的变量储存在主内存中
    • 本地内存:每个线程独立拥有的内存
    • 本地内存保存的是主内存的共享变量的副本
  • 垃圾回收
    • 根搜索算法(可达性分析算法)从 GC ROOT 结点沿着引用链搜索,无法到达的结点即为不可到达的对象
  • 垃圾回收器
    • G1 收集器
      • 独特的分代垃圾回收器,分代 GC:分代收集器,同时兼顾年轻代和老年代
      • 使用分区算法,不要求 eden,年轻代或老年代的空间都连续
      • 并行性:回收期间,可由多个线程同时工作,有效利用多核 CPU 资源
      • 空间整理:回收过程中,会进行适当对象移动,减少空间碎片
      • 可预见性:G1 可选取部分区域进行回收,可见缩小回收范围,减少全局停顿
    • G1 收集器的过程
      • 初始标记(它标记了从 GC ROOT 开始直接可达的对象)Stop-The-World
      • 并发标记(从 GC Roots 开始对堆中对象进行可达性分析,找出存活对象)
      • 最终标记(标记那些在并发标记阶段发生变化的对象,将被回收)Stop-The-World
      • 筛选回收(首先对各个 Regin 的回收价值和成本进行排序,根据用户所期待的 GC 停顿时间指定回收计划,回收一部分 Region)Stop-The-World

Map

  • HashMap 的结构
    • 采用链地址法,当发生哈希冲突时使用链表解决
    • 当链表过长时,在 JDK1.8 下采用红黑树代替链表,当数据量较少时,转回链表
    • 当存储的数据量超过一个阈值后,HashMap 的哈希表长度将会扩容到原来的两倍,然后将所有的数据重新分配到新的内存中
  • HashMap 这样扩容的原因
    • 通过恰好两倍扩容,可以让原来在第 i 个链表的值被恰好分配到第 i 和第 2i 个链表的位置
    • 每一个值,只需要判断其哈希值在某个二进制位上的值即可直接完成分配
  • TreeMap 的结构
    • TreeMap 是一颗红黑树

设计模式

  • 设计原则
    • 开闭原则:对扩展开放,对修改关闭
    • 里氏替换原则:子类必须拥有所有的父类功能,子类可以开发自己的新功能
    • 依赖倒置原则:高层实现不能依赖低层实现,而是依赖于低层的抽象类
    • 单一职责原则:一个类应当只负责一个职责
    • 接口隔离原则:接口应该更小更具体,而不是去实现很庞大的借口来适应所有需求
    • 迪米特法则:避免与无关实体进行通信
    • 合成复用原则:尽量先使用组合或者聚合等关联,其次考虑继承
  • 设计模式
    • 创建型模式
      • 单例模式:限制一个类只能有一个实例
      • 原型模式:以一个此类型的实例为模版,通过拷贝内存中的二进制值来直接创建一个对象
      • 工厂模式:将创建对象的过程由另一个类进行封装
      • 建造者模式:将一个复杂的对象分为多个简单的对象的组合,并实现将多个小对象进行拼装的过程
    • 结构型模式
      • 代理模式:使得两个对象之间不能直接引用访问,只能通过第三方,可以保护目标对象,扩展目标对象的功能
      • 适配器模式:将一个类的接口转换为另一个类的借口,通常是为了适配两个接口的对接问题
      • 桥接模式:将抽象与实现分离,使得他们可以独立变化,用组合关系来代替继承关系
      • 装饰器模式:为类增加新的功能的同时,避免了继承
      • 外观模式:隐藏系统的复杂性
      • 享元模式:重复 使用已经创建的同类对象
      • 组合模式
  • 行为型模式
    • 模板方法模式:仅实现一个操作中的骨干步骤,具体步骤由其子类实现
    • 策略模式
    • 命令模式
    • 责任链模式
    • 状态模式
    • 观察者模式
    • 中介者模式
    • 迭代器模式
    • 访问者模式
    • 备忘录模式
    • 解释器模式

String

  • String 类型
    • String 类型是不可变的,对 String 类型进行操作时,会重新生成新的 String 对象
  • StringBuilder StringBuffer
    • StringBuilder StringBuffer 都是可变的
    • StringBuilder 没有线程同步,存在线程安全问题,但是其效率略高于 StringBuffer
    • StringBuffer 能够保证线程安全,但效率较低

接口和抽象类

  • 接口和抽象类的区别
    • 抽象类可以写非抽象方法,而接口类只能有抽象方法
    • 一个类只能继承自一个抽象类,而一个类能实现多个接口
    • 继承是一个“是不是”的关系,而接口实现则是“有没有”的关系

构造函数

  • 子类实例化总是默认调用父类的无参构造方法
    • 为了让父类初始化属性和方法

equals

  • equals==的区别
    • ==对于基本类型时,比较的是两个对象的值是否相同,而对于对象时,则比较的是这两个引用是否指向了同一个对象
    • equals则可以由此类进行重写,使得其满足正常的比较关系。若不进行重写,则与==等价
  • equalshashCode为什么需要同时进行重写
    • hashCodeObject类下的默认行为是将此值的地址取出作为hashCode,但这与hashCode本意不同,hashCode的值应当满足对于任意 x x.equals(y) = true,则x.hashCode() = y.hashCode(),所以当重写equals时,通常意味着这个值的相等概念与==不同。所以必然需要重写hashCode避免在hashMap中出现意料之外的情况

CopyOnWrite

写入时复制(CopyOnWrite,简称 COW)思想是计算机程序设计领域中的一种通用优化策略。其核心思想是,如果有多个调用者(Callers)同时访问相同的资源(如内存或者是磁盘上的数据存储,他们会共同获取相同的指针指向相同的资源,直到某个调用者修改资源内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently。此做法主要的优点是如果调用者没有修改资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源。

通俗易懂的讲,写入时复制技术就是不同进程在访问同一资源的时候,只有更新操作,才会去复制一份新的数据并更新替换,否则都是访问同一个资源。

JDK CopyOnWriteArrayList/CopyOnWriteArraySet 容器正是采用了 COW 思想,它是如何工作的呢?简单来说,就是平时查询的时候,都不需要加锁,随便访问,只有在更新的时候,才会从原来的数据复制一个副本出来,然后修改这个副本,最后把原数据替换成当前的副本。修改操作的同时,读操作不会被阻塞,而是继续读取旧的数据。这点要跟读写锁区分一下。


最后更新: 2023年10月8日 15:31:56
创建日期: 2023年9月6日 10:51:03
回到页面顶部