Java 并发面试三
ThreadLocal
ThreadLocal 有什么用?
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢?
JDK 中自带的ThreadLocal
类正是为了解决这样的问题。 ThreadLocal
类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal
类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢?
JDK 中自带的ThreadLocal
类正是为了解决这样的问题。 ThreadLocal
类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal
类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。
JMM(Java 内存模型)相关的问题比较多,也比较重要,于是我单独抽了一篇文章来总结 JMM 相关的知识点和问题:JMM(Java 内存模型)详解 。
Java 泛型(Generics) 是 JDK 5 中引入的一个新特性。使用泛型参数,可以增强代码的可读性以及稳定性。
编译器可以对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。比如 ArrayList<Person> persons = new ArrayList<Person>()
这行代码就指明了该 ArrayList
对象只能传入 Person
对象,如果传入其他类型的对象就会报错。
典型问题
面向对象编程和面向过程编程有什么区别?
知识点
二者的主要区别在于解决问题的方式不同:
另外,面向对象开发的程序一般更易维护、易复用、易扩展。
Java 容器框架主要分为 Collection
和 Map
两种。其中,Collection
又分为 List
、Set
以及 Queue
。
《阿里巴巴 Java 开发手册》的描述如下:
判断所有集合内部的元素是否为空,使用
isEmpty()
方法,而不是size()==0
的方式。
这是因为 isEmpty()
方法的可读性更好,并且时间复杂度为 O(1)。
绝大部分我们使用的集合的 size()
方法的时间复杂度也是 O(1),不过,也有很多复杂度不是 O(1) 的,比如 java.util.concurrent
包下的某些集合(ConcurrentLinkedQueue
、ConcurrentHashMap
...)。
Hashtable 是早期 Java 类库提供的一个哈希表实现,本身是同步的,不支持 null 键和值,由于同步导致的性能开销,所以已经很少被推荐使用。
HashMap 是应用更加广泛的哈希表实现,行为上大致上与 HashTable 一致,主要区别在于 HashMap 不是同步的,支持 null 键和值等。
二者的主要差别如下:
HashMap | Hashtable | |
---|---|---|
线程安全 | 非线程安全 | 线程安全(主要方法都用 synchronized 修饰) |
效率 | 性能好 | 性能差:互斥锁,势必影响性能 |
初始化容量 | 初始容量为 16 | 初始容量为 11 |
扩容方式 | 2N(N 为当前容量) | 2N + 1 |
是否允许空值 | 允许存储 null 的 key 和 value | 不允许存储 null 的 key 和 value |
无论是通过引用计算算法判断对象的引用数量,还是通过可达性分析算法判断对象的引用链是否可达,判定对象是否可被回收都与引用有关。
Java 具有四种强度不同的引用类型:
(1)强引用
典型问题
Oracle JDK 和 Open JDK 有什么区别?
知识点
OpenJDK | Oracle JDK | |
---|---|---|
是否开源 | 完全开源 | 闭源 |
是否免费 | 完全免费 | JDK8u221 之后存在限制 |
更新频率 | 一般每 3 个月发布一个版本;不提供 LTS 服务 | 一般每 6 个月发布一个版本;大概每三年推出一个 LTS 版本 |
功能性 | Java 11 之后,OracleJDK 和 OpenJDK 的功能基本一致 | |
协议 | GPL v2 | BCL/OTN |
典型问题
知识点
并发和并行是最容易让新手费解的概念,那么如何理解二者呢?其最关键的差异在于:是否是同时发生: