【手册】Java开发手册 - hippowc/hippowc.github.io GitHub Wiki

Java相关

Java基础

Java数据类型

  • 8种基本数据类型
    • 转换关系:byte→short(char)→int→long→float→double
  • 包装类型:基本类型对应的类类型
    • 优势:提供了一系列实用的对象操作;集合不允许存放基本数据类型;
  • String
    • String类是final类,不可被继承;String的value也是final类型,对象值不可改变
      • 为何String对象不可变
        • 安全性:String类型很常用,譬如在参数、hashmap的key。要防止误操作改变变量的值
        • 提高使用效率:字符串常量池
      • String创建的方法
        • 在常量池中创建:如果常量池中有则直接返回引用
          • 使用引号创建:"string"
          • 使用String的intern方法
        • 其他方法都是在堆中创建String对象
    • String,StringBuilder,StringBuffer
      • 少量操作:String,单线程大量操作:StringBuilder,多线程大量操作:StringBuffer
问题:
  • 装箱和拆箱的区别
    • 装箱:将原始类型转为包装类型;拆箱:将包装类型转为原始类型
  • String、StringBuilder、StringBuffer 的区别?
  • String 为什么要设计为不可变类?
  • Integer 和 int 的区别?
  • String 字符串修改实现的原理?
    • 修改值得是通过“+”拼接,其原理是转为StringBuilder,调用append,最后toString
  • String str = "i" 与 String str = new String("i") 一样吗?
    • 不一样,前者在常量池创建,后者先在常量池创建后在堆中创建
  • String 类的常用方法都有那些?
  • final 修饰 StringBuffer 后还可以 append 吗?
    • 可以

类与对象

  • 类加载顺序
    • 父类(静态变量、静态语句块)- 子类(静态变量、静态语句块)- 父类(实例变量、普通语句块)- 父类(构造函数)- 子类(实例变量、普通语句块)- 子类(构造函数)
  • 对象通用方法
    • equals:重写需要注意 对称性、传递性、一致性
    • hashCode:根据对象的地址或者字符串或者数字算出来的int类型的数值
    • toString
    • clone:用于拷贝,需要自己实现
      • 浅拷贝:返回同一个引用的对象
      • 深拷贝:返回不同引用的对象
    • wait、notify、notifyAll
问题:
  • == 和 equals 的区别?
  • 两个对象的 hashCode() 相同,则 equals() 也一定为 true 吗?
  • 为什么重写对象的 equals() 就一定要重写 hashCode() 方法?
    • 很多地方譬如Set,HashMap都是通过hashcode去判断两个对象是否是一样的
  • 如何实现对象的克隆?深克隆和浅克隆的区别?

面向对象相关

  • 面向对象三个特性:封装、继承、多态
  • 封装:封装只公开某些对外接口,隐藏具体实现细节
    • 目的:增加安全性,简化编程
    • 主要通过权限修饰符实现
      • 访问权限修饰符:private(仅自己可见)、protected(子类可见)、public(均可见)以及默认(包内可见)
  • 继承:继承是软件复用的一种形式。使用继承可以复用现有类的数据和行为,为其赋予新功能而创建出新类。
    • 目的:实现代码的复用
      • super 关键字
        • 访问父类的构造函数;访问父类的成员
        • 泛型中用于约束泛型的下界。如< ? super Apple>
      • 抽象类
        • 如果一个类中包含抽象方法,那么这个类必须声明为抽象类。
        • 抽象类和抽象方法都使用 abstract 关键字进行声明
        • 抽象类的实现目的,是代码复用,一种模板设计的方式;拓展继承该抽象类的模块的类的行为功能(开放闭合原则)
      • 接口
        • 接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected
        • 接口的字段默认都是 static 和 final 的
        • Java 8 开始,接口也可以拥有默认的方法实现
        • 约束继承该接口的类行为(依赖倒置原则)
  • 多态:右侧同一个引用的同一个方法,由于左侧实现不同,在运行时的表现也不同
    • 目的:可扩展性、可维护性
    • 实现手段
      • 子类重写父类的方法
      • 不同的类实现接口
    • 重写(Override):存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法
      • 子类方法的访问权限必须大于等于父类方法;
      • 子类方法的返回类型必须是父类方法返回类型或为其子类型
      • 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。
    • 重载(Overload):存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同
问题
  • 解释下什么是面向对象?面向对象和面向过程的区别?
  • 面向对象的三大特性?分别解释下?
  • 重载和重写的区别?
  • 抽象类和接口有什么区别?
  • super 关键字的作用

Java其他重要关键字

  • final
    • 修饰变量:
      • 基本类型,数值不可变
      • 引用类型,引用不可变,但被引用的对象内容可以变
    • 修饰方法:该方法不能被子类重写
    • 修饰类:该类不允许被继承
  • static
    • 修饰变量:变量属于类,通过类访问,所有对象共享,存储在方法区
    • 修饰方法:类加载完成后即可用,不依赖实例
    • 修饰语句块:类初始化的时候运行一次
    • 修饰内部类:不依赖类实例
问题
  • Java 中是否可以重写一个 private 或者 static 方法?
  • final、finally、finalize 的区别
  • static 关键字的作用
  • 静态变量和实例变量的区别?

反射

  • 通过反射机制,可以在运行时访问java对象的属性、方法、构造函数等
  • 应用场景
    • 实现通用框架
    • 动态代理、面向切面
    • 注解
  • 缺点
    • 性能开销、破坏封装性
  • 常用操作
    • 获取Class对象:Class对象有jvm生成,可以获悉类的结构
      • Class.forName方法
      • 类名 + .class
      • Object 的 getClass 方法
    • 实例操作
      • instanceOf 查看实例类型
      • newInstance 创建实例
  • 动态代理
    • jdk动态代理
      • 代理类实现 InvocationHandler 并重写 invoke 方法;在 invoke 方法中将对方法进行处理
    • cglib动态代理
      • 借助了 ASM Java 字节码框架去进行字节码增强操作
问题
  • Java 中的反射是什么意思?有哪些应用场景?
  • 反射的优缺点?
  • Java 中的动态代理是什么?有哪些应用?
  • 怎么实现动态代理?

java异常

  • Throwable表示任何可以作为异常抛出的类
    • Error
      • Error 用来表示 JVM 无法处理的错误
    • Exception
      • 受检异常 :代码需强制处理,否则编译不过;一般异常非代码导致,譬如IO异常
      • 运行时异常(runtime exception):不强制处理;一般可以通过代码规避,譬如空指针
  • finally关键字
    • 无论有无异常发生,finally语句一定会被执行。
    • 如果try语句中有return,finally执行方式
      • 先将返回值保存在局部变量,执行finally,完后返回return值
      • 如果finally中有return,使用finally的return
  • 子线程异常
    • 子线程设计理念:线程的问题应该线程自己本身来解决,而不要委托到外部。
    • 线程不能抛出任何受检异常,但是可以抛出Error和运行时异常,但是主线程捕获不到
    • 如果主线程想要获取子线程异常,可以通过列表返回给主线程
问题
  • finally 块中的代码什么时候被执行?
  • finally 是不是一定会被执行到?
  • try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
  • try-catch-finally 中那个部分可以省略?
  • Error 和 Exception 的区别?
  • 运行时异常与受检异常有何异同?
  • throw 和 throws 的区别?
  • 常见的异常类有哪些?
  • 主线程可以捕获到子线程的异常吗?
    • 一般主线程捕获不到子线程的异常

泛型

泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。

  • 泛型分类
    • 泛型类
    • 泛型接口
    • 泛型方法
  • 类型擦除
    • Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。
问题
  • Java 的泛型是如何工作的? 什么是类型擦除?
  • 什么是泛型中的限定通配符和非限定通配符 ?

序列化

  • transient:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。
  • 序列化ID:serialVersionUID决定着是否能够成功反序列化,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。
  • 序列化协议
    • 二进制
      • JDK自带:不支持跨语言、性能差,不常用
      • ProtoBuf
      • hessian
    • 文本
      • Json
      • Xml
问题
  • 什么是 Java 的序列化,如何实现 Java 的序列化?
  • 什么情况下需要序列化?

其他Java基础问题

JDK、JRE、JVM 三者之间的关系? 构造方法有哪些特性? 在 Java 中定义一个不做事且没有参数的构造方法有什么作用? Java 中创建对象的几种方式? short s1 = 1;s1 = s1 + 1;有什么错?那么 short s1 = 1; s1 += 1;呢?有没有错误? switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上? & 和 && 的区别? Java 中的参数传递时传值呢?还是传引用? Java 中的 Math.round(-1.5) 等于多少? 字节和字符的区别? Java 中的 IO 流的分类?说出几个你熟悉的实现类? 字节流和字符流有什么区别? BIO、NIO、AIO 有什么区别?

java容器

  • 总体分为2类
    • 实现Collection接口
      • List接口
        • Vector
          • Stack
        • ArrayList
        • LinkedList
      • Queue接口
        • LinkedList
      • Set接口
        • HashSet
        • TreeSet
    • 实现Map接口
      • HashMap
        • LinkedHashMap
      • HashTable
        • Properties
      • SortedMap
        • TreeMap
  • 使用场景
    • 键值对元素使用Map
      • 不需排序使用HashMap
      • 需要排序使用TreeMap
      • 并发使用ConcurrentHashMap
    • 只有元素使用Collection
      • 保证元素唯一使用HashSet或TreeSet
      • 不需要保证唯一使用LinkedList或ArrayList
  • 快速失败(fail-fast):
    • 在使用迭代器对集合对象进行遍历的时候,如果A线程对集合进行遍历,正好B线程对集合进行修改(增加、删除、修改)则A线程会抛出ConcurrentModificationException异常。
    • java.util下都是快速失败
    • 原理:
      • 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量
      • 集合在被遍历期间如果内容发生变化,就会改变modCount的值。
      • 迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量,如果变化则失败
  • 安全失败(fail-safe):
    • 采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
    • java.util.concurrent包下的容器都是安全失败
    • 原理:
      • 由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到
      • 迭代器并不能访问到修改后的内容

List

  • ArrayList:底层为数组,不支持并发
  • Vector:底层为数组,支持并发
  • LinkedList:双向链表(1.6为循环链表,1.7后取消了循环)
  • ListIterator: 更强大的Iterator的子类,用于各种List类的访问,并支持双向移动。
  • Stack:栈
  • CopyOnWriteArrayList
    • 读写分离,写数据加ReenTrantLock并新建数组,完成后替换旧数组

Map

  • HashMap

    • JDK1.8 之前 HashMap 由数组+链表组成的,JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树
    • put操作
      • 判断是否需要扩容
      • 计算hash后元素是否存在,不存在则直接添加
      • 替换或添加
        • 数组中、链表中、红黑树中
    • 扩容
    • get操作
  • LinkedHashMap

    • LinkedHashMap 继承自 HashMap
    • 增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑
    • 构造函数增加accessOrder参数,可以基于此实现LRU
      • 默认为false,新插入的元素放在最后,为true时,新插入或新访问的元素都放在最后
  • Hashtable:数组+链表组成,与HashMap区别,线程安全

  • ConcurrentHashMap: 线程安全的Map

    • 数据结构与HashMap一致
    • 使用自旋、配合synchronized及CAS 来保证并发安全
  • TreeMap: 基于红黑树的实现(自平衡的排序二叉树),而非数组加链表。“键”或“键值对”的次序是由Comparable或Comparator决定的。

Set

  • HashSet:元素无序,唯一;基于 HashMap 实现的,底层采用 HashMap 来保存元素,
    • LinkedHashSet:是 HashSet 的子类,并且其内部是通过 LinkedHashMap 来实现的
  • TreeSet:元素有序,唯一;基于红黑树(自平衡的排序二叉树)

相关问题

  • Java 中常用的容器有哪些?
  • ArrayList 和 LinkedList 的区别?
  • ArrayList 实现 RandomAccess 接口有何作用?为何 LinkedList 却没实现这个接口?
  • ArrayList 的扩容机制?
  • Array 和 ArrayList 有何区别?什么时候更适合用 Array?
  • HashMap 的实现原理/底层数据结构?JDK1.7 和 JDK1.8
  • HashMap 的 put 方法的执行过程?
  • HashMap 的 get 方法的执行过程?
  • HashMap 的 resize 方法的执行过程?
  • HashMap 的 size 为什么必须是 2 的整数次方?
    • 为了加快哈希计算以及减少哈希冲突
    • 通过哈希值计算数组下标可以通过取模,也可以通过&运算,但是% 计算比 & 慢很多
    • n是2的次幂,所以 n-1 通过 二进制表示,永远都是尾端以连续1的形式表示(00001111,00000011)当(n - 1) 和 hash 做与运算时,会保留hash中 后 x 位的 1
  • HashMap 多线程死循环问题?
    • 多线程情况下出现
    • 两个线程操作rehash,导致链表部分出现环,再get时就会死循环
  • HashMap 的 get 方法能否判断某个元素是否在 map 中?
  • HashMap 与 HashTable 的区别是什么?
  • HashMap 与 ConcurrentHashMap 的区别是什么?
  • HashTable 和 ConcurrentHashMap 的区别?
  • ConcurrentHashMap 的实现原理是什么?
  • HashSet 的实现原理?
  • HashSet 怎么保证元素不重复的?
    • 插入时比较hash值和元素值,如果存在则不插入
  • LinkedHashMap 的实现原理?
  • Iterator 怎么使用?有什么特点?
  • Iterator 和 ListIterator 有什么区别?
  • Iterator 和 Enumeration 接口的区别?
  • fail-fast 与 fail-safe 有什么区别?
  • Collection 和 Collections 有什么区别?

Java IO

  • IO原理
    • 应用程序通过系统调用让内核执行IO操作
    • 内核等待IO设备准备好数据
    • 内核将数据从内核空间拷贝的用户空间
  • UNIX IO模型
    • 同步阻塞
      • 应用程序发起read调用后,会一直阻塞,直到内核把数据拷贝到用户空间
    • 同步非阻塞
      • 应用程序会一直发起 read 调用,等待数据从内核空间拷贝到用户空间的这段时间里,线程依然是阻塞的,直到在内核把数据拷贝到用户空间。
      • 问题:应用程序不断进行 I/O 系统调用轮询数据是否已经准备好的过程是十分消耗 CPU 资源的。
    • IO多路复用
      • 线程首先发起 select 调用,询问内核数据是否准备就绪,等内核把数据准备好了,用户线程再发起 read 调用。
      • read 调用的过程(数据从内核空间 -> 用户空间)还是阻塞的。
    • 信号驱动IO
    • 异步IO
  • JavaIO模型
    • BIO,同步阻塞IO
    • NIO,同步非阻塞IO

Java并发

Java线程基础

  • 线程状态:新建(NEW)、可运行(RUNABLE)、阻塞(BLOCKED)、无限期等待(WAITING)、限期等待(TIMED_WAITING)、死亡(TERMINATED)
    • 阻塞和等待的区别在于,阻塞是被动的,它是在等待获取 monitor lock。而等待是主动的,通过调用 Object.wait() 等方法进入。
    • 限期等待无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。
  • 线程方法与状态切换
    • sleep
      • 导致当前线程休眠,sleep(long)会导致线程进入 TIMED-WATING 状态
      • 不会释放当前占有的锁
    • wait
      • 不带时间常数的wait 方法进入WAITING状态;带时间常数的wait 进入TIME-WAITING状态。
      • 主动让出锁
    • yield
      • 会使当前线程让出 CPU 执行时间片,与其他线程一起重新竞争 CPU 时间片
    • join
      • 当前线程转为阻塞状态,等到另一个线程结束,当前线程再由阻塞状态变为就绪状态
  • 创建线程方式
    • 实现Callable接口
    • 实现Runnable接口
    • 继承Thread类
  • 中断线程的方式
    • 与Runnable相关: 主要是通过调用Thread.interrupt方法实现。
    • 与Callable相关:可以调用Future对象的cancel(true)方法。
    • 调用ExecutorService的shutdown的方法
  • 线程池
    • 线程池创建
      • 创建ThreadPoolExecutor类
        • 如果运行的线程少于 corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的;
        • 如果运行的线程大于 corePoolSize,新任务放入workQueue
        • 如果corePoolSize和workQueue都满了,但小于maximumPoolSize,再次创建新线程
        • 都满了,执行拒绝策略
    • 拒绝策略
      • ThreadPoolExecutor.AbortPolicy:抛出 RejectedExecutionException来拒绝新任务的处理
      • ThreadPoolExecutor.CallerRunsPolicy:用启动threadPool的线程执行新的请求。
      • ThreadPoolExecutor.DiscardPolicy: 不处理新任务,直接丢弃掉
      • ThreadPoolExecutor.DiscardOldestPolicy: 此策略将丢弃最早的未处理的任务请求
    • 线程池队列
      • SynchronousQueue:没有容量,是无缓冲等待队列
      • LinkedBlockingQueue:无界缓存等待队列
      • ArrayBlockingQueue:有界缓存等待队列,可以指定缓存队列的大小
    • 相关方法
      • execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否
      • submit()方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功
      • shutdown() :关闭线程池,线程池的状态变为 SHUTDOWN。线程池不再接受新任务了,但是队列里的任务得执行完毕
      • shutdownNow() :关闭线程池,线程的状态变为 STOP。线程池会终止当前正在运行的任务
      • isShutDown 当调用 shutdown() 方法后返回为 true
      • isTerminated 当调用 shutdown() 方法后,并且所有提交的任务完成后返回为 true
    • 线程池配置思路
      • CPU密集型任务应配置尽可能小的线程,如配置CPU个数的线程数+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断
      • IO密集型任务应配置尽可能多的线程,因为IO操作不占用CPU,不要让CPU闲下来,应加大线程数量,如配置两倍CPU个数+1
  • ThreadLocal
    • 数据结构
      • 为TheadLocalMap,类似HashMap,不过仅使用数组
      • key为ThreadLocal的弱引用,value为存储的值
    • 应用场景
      • Spring采用ThreadLocal的方式,来保证单个线程中的数据库操作使用的是同一个数据库连接
      • web应用通过ThreadLocal管理用户上下文

java并发原理

  • 线程安全问题原因

    • 主内存与工作内存工作不一致
    • 指令重排:为了提高性能,编译器和处理器常常会对指令进行重排序
      • 编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖性关系的两个操作的执行顺序
      • happens-before规则
  • 线程建通信方式

    • 共享内存:java使用该种方式
      • java内存模型中,所有变量都放在主内存,当线程使用变量时,需要将主内存中变量复制到自己的工作空间
    • 消息传递
  • 使用并发时可能会出现的三个问题

    • 可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到,我们称为可见性
    • 原子性:一个或者多个操作在 CPU 执行的过程中不被中断
    • 有序性:有序性指的是程序按照代码的先后顺序执行
  • volatile:当读一个 volatile 变量时, JMM 会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量

  • Atomic原子类:原子类主要基于CAS操作实现,同时使用 volatile 保证可见性

    • AtomicInteger、AtomicLong、AtomicBoolean
    • AtomicReference
    • Atomic*Array
    • synchronized:synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。非公平,悲观,独享,互斥,可重入的重量级锁
      • 原理
        • synchronized通过对象内部的监视器锁实现,监视器锁是依赖操作系统的互斥锁实现,操作系统进行线程切换需要用户态到内核态转换,成本比较高
      • JDK对synchronized锁进行的优化
        • 偏向锁:程序第一次执行到synchronized时,锁对象变为偏向锁,即偏向于第一个获得锁的线程,执行完不释放锁,如果下次还是该线程执行,则不需要重新加锁,效率高
        • 轻量级锁:有第二个线程加入锁竞争时,偏向锁升级为轻量级锁,未获得锁的线程,会一直循环判断是否能获得锁,称为自旋。所以轻量级锁是一种自旋锁。默认循环10次
        • 重量级锁:如果锁竞争激烈,循环了很久还未获得,则升级为重量级锁,线程自动挂起,等待唤醒
          • 线程挂起、唤醒需要CPU切换上下文,涉及到用户态到内核态转换,成本高
      • 锁范围
        • 修饰普通实例方法:锁的是当前实例对象,通常指 this
        • 修饰静态方法:锁的是当前类的 Class 对象
        • 修饰同步代码块:锁的是括号内对象
    • Lock接口
      • WriteLock 写锁
      • ReadLock 读锁
      • ReentrantLock 可重入锁:默认非公平但可实现公平的,悲观,独享,互斥,可重入,重量级锁。
        • 获取锁的方式
          • lock:获得锁立即返回,未获得锁则休眠等待
          • tryLock:获得锁立即返回true,未获得锁立即返回false
          • lockInterruptibly:获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到获取锁定,或者当前线程被别的线程中断
  • 不加锁

    • CAS(compare and swap):不阻塞线程,可以提高吞吐率,但也有其问题
      • 原理
        • 读取到一个值为 A ,在要将这个值更新为B 之前,检查是否等于 A (比较),如果是则将 A 更新为 B(交换) ,否则什么都不做
        • 自旋+JNI(譬如compareAndSwapInt)实现
      • 劣势
        • 竞争激烈时,循环开销大,耗费cpu资源
        • 智能保证一个变量同步
  • 线程安全思路

    • 无状态类(不包含成员变量),或状态不可变(final关键字)
    • 使用volatile,保证可见性,但不能保证线程安全
    • 加锁
      • 锁竞争激烈:悲观锁,synchronized,Lock
      • 锁竞争不激烈:乐观锁,cas
    • 原子类
  • AQS: AbstractQueuedSynchronizer,抽象队列同步器,是构建锁或者其他同步组件的基础框架

    • 核心思想
      • 如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。
      • 如果被请求的共享资源被占用,将暂时获取不到锁的线程加入到队列中。
      • 当资源释放,从队列中取出排队线程执行
    • 数据结构
      • Node:双向队列,封装了请求共享资源的线程
      • volatile int state,用来表示同步的状态。state = 0 表示锁空闲,>0 表示锁已被占用。通过CAS完成对state的修改
        • 支持模式
          • 共享:
            • 资源允许多个线程同时访问
            • state初始化为n,通过判断state是否大于0,判断同步状态,若大于0,通过CAS自减
          • 独占:
            • 资源只能一个线程访问
            • state初始化为1
      • 模板方法
        • aqurie:模板方法会完成添加队列、线程阻塞等逻辑
          • 同步器实现(需自己实现) tryAcquire:主要设置state
        • release: 模板方法
          • 同步器实现(需自己实现)tryRelease:设置state
    • 应用场景
      • ReentrantLock、ReentrantReadWriteLock、Worker
      • Semaphore
  • 常用并发工具

    • Semaphore:信号量通常用来限制线程可以同时访问的(物理或逻辑)资源数量。
    • CountDownLatch 一种非常简单、但很常用的同步辅助类。其作用是在完成一组正在其他线程中执行的操作之前,允许一个或多个线程一直阻塞。
    • CyclicBarrier 一种可重置的多路同步点,它允许一组线程互相等待,直到到达某个公共的屏障点
    • Exchanger允许两个线程在某个汇合点交换对象,在某些管道设计时比较有用。

相关问题

并行和并发有什么区别? 线程和进程的区别? 守护线程是什么? 创建线程的几种方式? Runnable 和 Callable 有什么区别? 线程状态及转换? sleep() 和 wait() 的区别? 线程的 run() 和 start() 有什么区别? 在 Java 程序中怎么保证多线程的运行安全? Java 线程同步的几种方法? Thread.interrupt() 方法的工作原理是什么? 谈谈对 ThreadLocal 的理解? 在哪些场景下会使用到 ThreadLocal? 说一说自己对于 synchronized 关键字的了解? 如何在项目中使用 synchronized 的? 说说 JDK1.6 之后的 synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗? 谈谈 synchronized 和 ReenTrantLock 的区别? synchronized 和 volatile 的区别是什么? 谈一下你对 volatile 关键字的理解? 说下对 ReentrantReadWriteLock 的理解? 说下对悲观锁和乐观锁的理解? 乐观锁常见的两种实现方式是什么? 乐观锁的缺点有哪些? CAS 和 synchronized 的使用场景? 简单说下对 Java 中的原子类的理解? atomic 的原理是什么? 说下对同步器 AQS 的理解? AQS 的原理是什么? AQS 对资源的共享模式有哪些? AQS 底层使用了模板方法模式,你能说出几个需要重写的方法吗? 说下对信号量 Semaphore 的理解? CountDownLatch 和 CyclicBarrier 有什么区别? 说下对线程池的理解?为什么要使用线程池? 创建线程池的参数有哪些? 如何创建线程池? 线程池中的的线程数一般怎么设置?需要考虑哪些问题? 执行 execute() 方法和 submit() 方法的区别是什么呢? 说下对 Fork和Join 并行计算框架的理解? JDK 中提供了哪些并发容器? 谈谈对 CopyOnWriteArrayList 的理解? 谈谈对 BlockingQueue 的理解?分别有哪些实现类? 谈谈对 ConcurrentSkipListMap 的理解?

Java底层

jvm

  • jvm:内存的分配与释放等操作有jvm控制
    • 数据结构
      • 线程私有区
        • 虚拟机栈:所有java方法的调用通过该栈来实现(除本地方法)
        • 本地方法栈:所有native方法(本地方法)通过该栈来实现
        • 程序计数器:当前线程所执行的字节码的行号指示器,解释器通过改变计数器值来选取下一条指令
      • 线程共享区
        • 堆:存储对象和数组实例,是垃圾收集器管理的主要区域
          • 新生代
            • Eden
            • Survivor1
            • Survivor2
          • 老生代
        • 方法区(jdk1.8之前)
          • 永久代(jdk1.8之前)
            • 类信息、字段信息、方法信息
            • 常量、静态变量
      • 本地内存
        • 直接内存
        • 元空间(jdk1.8之后)
          • 新的方法区实现
  • 对象分配与回收:Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收
    • Gc类型
      • 新生代收集(Minor GC / Young GC):只对新生代进行垃圾收集;
      • 老年代收集(Major GC / Old GC):只对老年代进行垃圾收集。需要注意的是 Major GC 在有的语境中也用于指代整堆收集;
      • 混合收集(Mixed GC):对整个新生代和部分老年代进行垃圾收集。
      • 整堆收集 (Full GC):收集整个 Java 堆和方法区。
    • 对象回收
      • 在Eden去分配,当Eden区空间不够时,发起Minor Gc
      • 在一次垃圾回收后,如果对象存活,则进入Survivor区,对象年龄为1
      • Survivor区每经过一次Minor Gc,对象年龄+1,年龄到一定程度(默认15),进入老生代
    • 判断对象死亡:不再被任何途径使用的对象
      • 引用计数:每当有个地方引用,计数+1,引用失效,计数-1
        • 问题:无法解决循环引用
      • 可达性算法:以GC Root对象为起点,整个搜索路径为引用链,如果对象不能到达GC Root,则认为死亡
        • 可作为GC Root的对象:
          • 虚拟机栈和本地方法栈引用的对象
          • 方法区静态属性和常量引用的对象
          • 所有同步锁持有的对象
    • 垃圾回收算法
      • 标记-删除:先标记,再统一删除
      • 标记-复制:每次标记完后,把存活的对象复制到另一块相同的区域,适用于年轻代,因为每次死亡对象多,复制成本低
      • 标记-整理:标记完后,把存活的对象向一端移动,适用于老年代

类与对象

  • 类加载 -类加载过程 - 加载 - 通过类全限定名获取类二进制字节流 - 将静态存储结构转为方法区的类结构 - 生成Class对象,作为类信息访问入口 - 连接 - 验证:验证类信息的格式、语义、字节码等 - 准备 - 为类变量分配内存,设置变量初始值 - 解析 - 将常量池内的符号引用替换为直接引用的过程 - 初始化 - 执行 clinit 方法
    • 类加载器
      • BootstrapClassLoader(启动类加载器):由C++实现,加载 %JAVA_HOME%/lib目录下的 jar 包和类或者被 -Xbootclasspath参数指定的路径中的所有类。
      • ExtensionClassLoader(扩展类加载器) :主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包。
      • AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。
    • 双亲委派模型:类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。
      • 自顶向下尝试加载类
      • 可以避免类的重复加载,保证了 Java 的核心 API 不被篡改
  • 对象加载
    • 类加载检查
      • 先检查常量池中是否有类的符号引用,若没有需先加载类
    • 分配内存
      • 对象内存大小根据类可确定
      • 从堆中分配内存
    • 初始化零值
    • 设置对象头
      • 包括类信息、对象哈希值、GC分代年龄等
    • init方法
  • 对象引用
    • 强引用:大部分引用是强引用,当对象有强引用时,不能被回收
    • 软引用:当内存空间不足时,会被回收
    • 弱引用:生命周期比软引用更短,不管内存是否足够,都会被回收
    • 虚引用:与无引用一样,主要用于跟踪对象回收

说一下 Jvm 的主要组成部分?及其作用? 谈谈对运行时数据区的理解? 堆和栈的区别是什么? 堆中存什么?栈中存什么? 为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗? Java 中的参数传递时传值呢?还是传引用? Java 对象的大小是怎么计算的? 对象的访问定位的两种方式? 判断垃圾可以回收的方法有哪些? 垃圾回收是从哪里开始的呢? 被标记为垃圾的对象一定会被回收吗? 谈谈对 Java 中引用的了解? 谈谈对内存泄漏的理解? 内存泄露的根本原因是什么? 举几个可能发生内存泄漏的情况? 尽量避免内存泄漏的方法? 常用的垃圾收集算法有哪些? 为什么要采用分代收集算法? 分代收集下的年轻代和老年代应该采用什么样的垃圾回收算法? 什么是浮动垃圾? 什么是内存碎片?如何解决? 常用的垃圾收集器有哪些? 谈谈你对 CMS 垃圾收集器的理解? 谈谈你对 G1 收集器的理解? 说下你对垃圾回收策略的理解/垃圾回收时机? 谈谈你对内存分配的理解?大对象怎么分配?空间分配担保? 说下你用过的 JVM 监控工具? 如何利用监控工具调优? JVM 的一些参数? 谈谈你对类文件结构的理解?有哪些部分组成? 谈谈你对类加载机制的了解? 类加载各阶段的作用分别是什么? 有哪些类加载器?分别有什么作用? 类与类加载器的关系? 谈谈你对双亲委派模型的理解?工作过程?为什么要使用 怎么实现一个自定义的类加载器?需要注意什么? 怎么打破双亲委派模型? 有哪些实际场景是需要打破双亲委派模型的? 谈谈你对编译期优化和运行期优化的理解? 为何 HotSpot 虚拟机要使用解释器与编译器并存的架构? 说下你对 Java 内存模型的理解? 内存间的交互操作有哪些?需要满足什么规则?

技术产品

ssm框架

spring

  • spring IOC
    • 控制反转:原来在程序中手动创建对象,现在需要什么对象由IOC提供,一个好处就是对象统一管理。
    • 依赖注入:将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。简化开发及对象的创建。
  • AOP:面向切面编程
    • Spring AOP:运行时增强,基于动态代理
      • 如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy
      • 对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib
    • AspectJ:编译时增强,基于字节码操作
    • 应用场景
      • Authentication 权限
      • Caching 缓存
      • Error handling 错误处理 等
  • bean作用域
    • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的
    • prototype : 每次请求都会创建一个新的 bean 实例。
      • 用多例,是为了防止并发问题
    • request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
    • session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效
  • Spring 循环依赖
    • 原理:对于普通的循环依赖如A 依赖B, B依赖A。在初始化A的时候,会实例化B,实例化B发现需要A的引用,这时候通过缓存返回A的引用。虽然A还未初始化完毕,但是由于是对象的引用,所以最终初始化完成的时候,两个对象均是初始化完整的。
    • 通过三级缓存实现
      • singletonObjects,一级缓存,存储的是所有创建好了的单例Bean
      • earlySingletonObjects,完成实例化,但是还未进行属性注入及初始化的对象
      • singletonFactories,提前暴露的一个单例工厂(一个获取对象的函数表达式),二级缓存中存储的就是从这个工厂中获取到的对象
        • 三级缓存为spring在循环依赖时存在aop而设计的
  • 事务管理
    • 事务关心的几个属性
      • 事务的传播行为:为了解决业务层方法之间互相调用的事务问题。
        • 默认REQUIRED:如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。
        • SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。
        • MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常IllegalTransactionStateException。
        • REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,延缓当前的事务。
        • NESTED:如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务。
        • NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。
        • NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。
      • 事务隔离级别:事务之间的隔离级别,一般至两个事务同时处理时,对事务内部数据处理的隔离情况
        • ISOLATION_DEFAULT :使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别.
        • ISOLATION_READ_UNCOMMITTED :最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
        • ISOLATION_READ_COMMITTED : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
        • ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
        • ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能
  • spingboot自动配置加载过程
    • Spring boot的配置自动加载主要通过@SpringBootApplication 中的 @EnableAutoConfiguration注解实现
    • AutoConfigurationImportSelector类的getAutoConfigurationEntry方法会扫描所有包下spring-autoconfigure-metadata.properties的属性
    • 通过@ConditionOn的系列注解并对比过滤符合当前配置的配置项,重新进行config的注解扫描添加需要的bean配置到BenDefinition中
  • spring处理http请求流程
    • 经过Servlet的filter进行过滤
    • 请求到 DispatcherServlet
    • DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler(也就是我们平常说的 Controller 控制器)
    • 处理器处理完业务后,会返回一个 ModelAndView 对象
  • BeanFactory和ApplicationContext
    • BeanFactory:负责配置、创建、管理bean,IOC功能的实现主要就依赖于该接口子类实现。
    • ApplicationContext 是 Spring 应用程序中的中央接口,用于向应用程序提供配置信息。它继承了 BeanFactory 接口 使用 Spring 框架的好处是什么? 解释下什么是 AOP? AOP 的代理有哪几种方式? 怎么实现 JDK 动态代理? AOP 的基本概念:切面、连接点、切入点等? 通知类型(Advice)型(Advice)有哪些? 谈谈你对 IOC 的理解? Bean 的生命周期? Bean 的作用域? Spring 中的单例 Bean 的线程安全问题了解吗? 谈谈你对 Spring 中的事物的理解? Spring 中的事务隔离级别? Spring 中的事物传播行为? Spring 常用的注入方式有哪些? Spring 框架中用到了哪些设计模式? ApplicationContext 通常的实现有哪些? 谈谈你对 MVC 模式的理解? SpringMVC 的工作原理/执行流程? SpringMVC 的核心组件有哪些? SpringMVC 常用的注解有哪些? @RequestMapping 的作用是什么? 如何解决 POST 请求中文乱码问题,GET 的又如何处理呢? SpringMVC 的控制器是不是单例模式,如果是会有什么问题,怎么解决? SpringMVC 怎么样设定重定向和转发的? SpringMVC 里面拦截器是怎么写的? SpringMVC 和 Struts2 的区别有哪些? 谈谈你对 MyBatis 的理解? MyBaits 的优缺点有哪些? MyBatis 与 Hibernate 有哪些不同? MyBatis 中 #{} 和 ${}的区别是什么? MyBatis 是如何进行分页的?分页插件的原理是什么? MyBatis 有几种分页方式? MyBatis 逻辑分页和物理分页的区别是什么? MyBatis 是否支持延迟加载?如果支持,它的实现原理是什么? 说一下 MyBatis 的一级缓存和二级缓存? Mybatis 有哪些执行器(Executor)? MyBatis 动态 SQL 是做什么的?都有哪些动态 SQL?能简述一下动态 SQL的执行原理不?