Java语言相关
Table of Contents
- Java
- JVM vs JDK vs JRE
- Java对象的创建过程
- JVM运行时数据区讲讲? JDK1.8默认的垃圾收集器是? CMS和G区别是什么? volatile有什么用?
- String a ="abc"; String b = new String("abc");问a=b是true还是false? a和b分别在什么内存区域?
- ArrayList和LinkedList区别? HashMap的底层实现?
- 红黑树
- HashMap线程不安全会导致什么问题?
- 如何避免HashMap在多线程环境下出现并发安全问题?
- Java是跨平台的吗? 虚拟机是跨平台的吗? 虚拟机用什么语言实现的?
- Synchroize和ReentrantLock的区别是? 应用场景是?
- AQS原理讲下?
- 常用的限流算法?令牌桶如何实现? 滑动窗口如何实现?
- 两个线程,顺序执行怎么做?
Java
- Java SE(Java Platform,Standard Edition): Java 平台标准版。
- Java EE(Java Platform, Enterprise Edition ):Java 平台企业版。
- Java ME(Java Platform,Micro Edition):Java 的微型版本,主要用于开发嵌入式消费电子设备的应用程序,例如手机、PDA、机顶盒、冰箱、空调等。Java ME 无需重点关注,知道有这个东西就好了,现在已经用不上了。
JVM vs JDK vs JRE
简单来说
,JRE 只包含运行 Java 程序所需的环境和类库,而 JDK 不仅包含 JRE,还包括用于开发和调试 Java 程序的工具。
- JVM(Java Virtual Machine)
- Java 虚拟机,是运行 Java 字节码的虚拟机。
- JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。
- 字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。
- JDK(Java Development Kit)
- 一个功能齐全的 Java 开发工具包,供开发者使用,用于创建和编译 Java 程序。
- 它包含了 JRE(Java Runtime Environment),以及编译器 javac 和其他工具,如 javadoc(文档生成器)、jdb(调试器)、jconsole(监控工具)、javap(反编译工具)等。
- JRE(Java Runtime Environment)
- 是运行已编译 Java 程序所需的环境,主要包含以下两个部分:
- JVM
- Java 基础类库(Class Library):一组标准的类库,提供常用的功能和 API(如 I/O 操作、网络通信、数据结构等)。
Java对象的创建过程
❶ 类加载检查
❷ 分配内存
❸ 初始化零值
❹ 设置对象头
❺ 执行init方法
JVM运行时数据区讲讲? JDK1.8默认的垃圾收集器是? CMS和G区别是什么? volatile有什么用?
- JVM 运行时数据区包括:程序计数器、Java 虚拟机栈、本地方法栈、Java 堆和方法区。
- JDK1.8 默认的垃圾收集器是:Parallel Scavenge(新生代)和 Parallel Old(老年代)。
- CMS(Concurrent Mark Sweep)和 G1(Garbage-First)是两种不同的垃圾收集器,它们的主要区别在于:
- 1. 算法不同:CMS 采用的是标记-清除算法,而 G1 采用的是标记-整理算法。
- 2. 适用场景不同:CMS 适用于对响应时间要求较高的应用,而 G1 适用于对内存空间要求较高的应用。
- 3. 性能不同:在相同的硬件环境下,G1 的性能通常比 CMS 更好。
- volatile 是 Java 中的一个关键字,它可以用来修饰变量。被 volatile 修饰的变量具有以下特点:
- 1. 可见性:当一个线程修改了一个被 volatile 修饰的变量时,其他线程能够立即看到这个修改。
- 2. 禁止指令重排序:volatile 可以禁止编译器和处理器对指令进行重排序,从而保证程序的执行顺序与代码的顺序一致。
String a ="abc"; String b = new String("abc");问a=b是true还是false? a和b分别在什么内存区域?
- 在这种情况下,`a == b` 的结果是 `false`。
- `String a = "abc"` 会在字符串常量池中创建一个字符串对象 `"abc"` ,然后 `a` 指向这个对象。
- `String b = new String("abc")` 会在堆内存中创建一个新的字符串对象,所以 `a` 和 `b` 指向不同的对象,因此 `a == b` 为 `false`。
- `a` 在字符串常量池,`b` 在堆内存中。
ArrayList和LinkedList区别? HashMap的底层实现?
- ArrayList 和 LinkedList 的主要区别在于数据结构和性能特点。
- ArrayList 基于动态数组实现,随机访问速度快,即在通过索引获取元素时效率高,但在插入和删除元素时,尤其是在中间位置,需要移动大量元素,效率较低。
- LinkedList 基于双向链表实现,插入和删除元素的效率高,特别是在链表头部和尾部操作时,但随机访问元素的效率低,因为需要从头或尾依次遍历。
- HashMap 的底层实现主要包括数组和链表(在 Java 8 中,当链表长度超过一定阈值会转换为红黑树)。
- 通过哈希函数计算键的哈希值,确定元素在数组中的存储位置。如果多个键的哈希值相同,就会以链表的形式存储在该位置。
红黑树
- 红黑树是一种自平衡的二叉查找树。在 Java 中,比如 TreeMap 和 TreeSet 的底层实现就可能用到红黑树。
- 红黑树的主要特点包括:节点要么是红色,要么是黑色;
- 根节点是黑色;每个叶子节点(NIL 节点)是黑色;
- 如果一个节点是红色,那么它的两个子节点都是黑色;
- 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
- 这些特性保证了红黑树在插入和删除操作时能在 O(log n) 的时间复杂度内重新自平衡,保持较好的性能。
HashMap线程不安全会导致什么问题?
- 可能会出现数据丢失的情况。当多个线程同时对 HashMap 进行扩容操作时,可能会导致某些元素丢失,没有被正确地重新映射到新的数组位置。
- 还可能出现数据不一致的问题。多个线程同时进行 put 操作时,可能会导致链表形成环,进而在后续的遍历操作中造成死循环。
- 另外,多线程并发读写 HashMap 时,可能会导致读到错误或不完整的数据。
如何避免HashMap在多线程环境下出现并发安全问题?
- 使用 ConcurrentHashMap:ConcurrentHashMap 是 Java 提供的线程安全的 HashMap 实现,它通过锁和分段锁的方式保证多线程环境下的安全。
- 使用 synchronized 关键字:可以在对 HashMap 进行操作的方法上添加 synchronized 关键字,以保证同一时间只有一个线程可以访问 HashMap。
- 使用 Collections.synchronizedMap()方法:可以将 HashMap 包装成一个线程安全的 Map,通过 Collections.synchronizedMap()方法来实现。
Java是跨平台的吗? 虚拟机是跨平台的吗? 虚拟机用什么语言实现的?
- Java 语言是跨平台的,这种跨平台性是通过 Java 虚拟机(JVM)来实现的。
- JVM 是 Java 实现跨平台的最核心部分,所有的 Java 程序会首先被编译为.class 的类文件,这种类文件可以在虚拟机上执行,也就是说 class 并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互。
- JVM 不是跨平台的,不同的操作系统需要安装对应的 JVM 版本。
- JVM 是用 C++语言实现的。
Synchroize和ReentrantLock的区别是? 应用场景是?
在 Java 中,synchronized 和 ReentrantLock 都是用于实现线程同步的机制,但它们有一些区别,包括:
- 实现方式:synchronized 是 Java 内置的关键字,通过 monitor 机制实现线程同步;而 ReentrantLock 是 Java 5 中引入的 Lock 接口的实现,通过 AQS (AbstractQueuedSynchronizer)实现线程同步。
- 灵活性:ReentrantLock 提供了比 synchronized 更灵活的锁定方式,例如可以实现公平锁、非公平锁、可重入锁等,还可以设置超时时间等。
- 性能:在某些情况下,ReentrantLock 的性能可能比 synchronized 更好,因为它可以避免一些不必要的线程阻塞和唤醒。
- 适用场景:synchronized 适用于简单的同步场景,例如单线程环境或对性能要求不高的场景;而 ReentrantLock 适用于复杂的同步场景,例如需要实现公平锁、可重入锁等的场景。
AQS原理讲下?
- AQS(AbstractQueuedSynchronizer)是 Java 中很多同步工具类的基础。
- AQS 的核心思想是一个先进先出(FIFO)的队列,用于存储等待获取锁的线程。
- 它维护了一个整数类型的状态变量 state ,用于表示锁的持有情况。获取锁和释放锁的线程通过修改这个状态变量来进行同步操作。
- 当一个线程尝试获取锁时,如果 state 为 0 且没有其他线程持有锁,那么该线程可以成功获取锁,并修改 state 的值;如果 state 不为 0 或者有其他线程持有锁,那么该线程会被加入到等待队列中阻塞等待。
- 当持有锁的线程释放锁时,会修改 state 的值,并唤醒等待队列中的一个或多个线程来重新竞争锁。
- AQS 还提供了诸如 tryAcquire 、 tryRelease 等模板方法,供具体的同步工具类去实现自己的获取锁和释放锁逻辑。
常用的限流算法?令牌桶如何实现? 滑动窗口如何实现?
- 常用的限流算法有 令牌桶 算法 、 算法 和 滑动窗口 算法。
令牌桶算法
- 实现思路
- 是有一个固定容量的桶,系统会以一定的速率向桶中放入令牌。
- 当请求到来时,如果桶中有足够的令牌,就允许请求通过并消耗一个令牌;
- 如果桶中没有令牌,就拒绝请求。
- 优缺点
- 能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。
- 适合单机限流,不适合分布式限流。
- 实现上需要更多的存储空间。
滑动窗口算法
- 实现思路
- 通常基于时间窗口和计数器。
- 将一段时间划分为多个小的时间窗口,每个窗口都有对应的请求数量计数器。
- 通过统计当前时间窗口及之前若干个窗口内的请求总数来判断是否限流。
- 优缺点
- 能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。
- 实现上需要更多的存储空间。
- 如果滑动窗口的精度越高,需要的存储空间就越大。
两个线程,顺序执行怎么做?
- `join` 方法可以让当前线程等待被调用 `join` 方法的线程执行完毕。