JAVA语言特性
概览
- 常用集合
- JUC
- 动态代理与反射
- 基础数据类型
- 对象引用
- 异常机制
- 版本差异
常用集合
1.Set
- HashSet
- LinkedHashSet
- TreeSet
2.List
- ArrayList
- LinkedList
3.Map
- HashMap
- TreeMap
HashMap 就是数组加链表实现的,数组中的每一项是一个链表。通过计算存入对象的 HashCode,来计算对象在数组中要存入的位置,用链表来解决散列冲突,链表中的节点存储的是键值对。
HashMap 的容量都是 2 的幂次方,这是因为可以通过按位与操作来计算余数,比求模要快。
HashMap 是非线程安全的,在多线程 put 的情况下,有可能在容量超过填充因子时进行 rehash,因为 HashMap 为了避免尾部遍历,在链表插入元素时使用头插法,多线程的场景下有可能会产生死循环。
JUC
JUC 是 Java 提供的用于多线程处理的工具类库
- AtomicXXX
包括 AtomicBoolean、AtomicLong、AtomicInteger 类,这是基本数据类型的原子类
AtomicLong 通过 unsafe 类实现,基于CAS。unsafe 类是底层工具类,JUC 中很多类的底层都使用到了 unsafe 包中的功能。unsafe 类提供了类似 C 的指针操作,提供 CAS 等功能。unsafe 类中的所有方法都是 native 修饰的。
- XXXAdder
包括 LongAdder、DoubleAdder、LongAccumulator、DoubleAccumulator 类,这是 JDK1.8 中提供的更高效的操作类
LongAdder 基于 Cell 实现,使用分段锁思想,是一种空间换时间的策略,更适合高并发场景;LongAccumulator 提供了比 LongAdder 更强大的功能,能够指定对数据的操作规则,例如可以把对数据的相加操作改成相乘操作。
- AtomicXXXReference
包括 AtomicReference 、AtomicStampedReference、AtomicMarkableReference 类,主要提供了对对象的原子读写功能
AtomicStampedReference 和 AtomicMarkableReference 用于解决 ABA 问题,分别基于时间戳和标记位来解决问题。
- LOCK
包括 ReentrantLock、ReentrantReadWriteLock、StampedLock 类
ReentrantLock 是独占锁,与Semaphore 是共享锁不一样,独占锁允许多个线程共享资源,适用于限制使用共享资源线程数量的场景
StampedLock 是JDK 1.8 改进的读写锁,是使用一种 CLH 的乐观锁,能够有效防止写饥饿。写饥饿是指在多线程读写时,读线程访问非常频繁,导致总是有读线程占用资源,写线程很难加上写锁
- 异步执行相关类
包括 Executors、ForkJoinPool、FutureTask、CompletableFuture 类
CompletableFuture 是 JDK 1.8 中提供的,可以支持流式调用,可以方便的进行多 future 的组合使用
ForkJoinPool是 JDK 1.7 中提供的,采用分治思想,将大任务分解成多个小任务处理,然后在合并处理结果。ForkJoinPool 的特点是使用工作窃取算法,可以有效平衡多任务时间长短不一的场景。
- 阻塞队列
包括 LinkedBlockingDeque、ArrayBlockingQueue 类
LinkedBlockingDeque 是双端队列,也就是可以分别从队头和队尾操作入队、出队。
ArrayBlockingQueue 单端队列,只能从队尾入队,队头出队。
- 多线程协作类
包括 CountDownLatch、CyclicBarrier、Semaphore
CountDownLatch 实现计数器功能,可以用来控制等待多个线程执行任务后进行汇总
CyclicBarrier 可以让一组线程等待至某个状态之后,再全部同时执行,一般在测试时使用,可以让多线程更好的并发执行
Semaphore 用来控制对共享资源的访问并发度
- 线程安全集合
ConcurrentHashMap、CopyOnWriteArrayList
ConcurrentHashMap 采用分段锁的思想来降低并发场景下的锁定发生频率,在 JDK1.7 与 1.8 中的实现差异非常大,1.7 中使用 Segment 进行分段加锁,降低并发锁定;1.8 中使用 CAS 自旋锁的乐观锁来提高性能,但是在并发度较高时性能会比较一般。1.8 中的 ConcurrentHashMap 引入了红黑树来解决 Hash 冲突时链表顺序查找的问题。红黑树的启用条件与链表的长度和 Map 的总容量有关,默认是链表大于 8 且容量大于 64 时转为红黑树
CopyOnWriteArrayList 通过写入数据时进行 copy 修改,然后更新引用的方式,来消除并行读写中的锁使用,比较适合读多写少,数据量比较小,但是并发非常高的场景
动态代理与反射
JDK 动态代理 Proxy.newProxyInstance()
基础数据类型
- byte
8 位,-128 ~ 127,默认值是 0
- char
16 位 Unicode 字符,0 ~ 65535
- short
16 位, -32768 ~ 32767,默认值是 0
- int
32 位,-2,147,483,648 ~ 2,147,483,647,默认值是 0
- long
64 位,-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807,默认值是 0
- float
单精度、32位、符合IEEE 754标准的浮点数,不能用来表示精确的值,默认值是 0.0f
- double
双精度、64 位、符合IEEE 754标准的浮点数,不能用来表示精确的值,默认值是 0.0d
- boolean
表示一位的信息,只有两个取值:true 和 false,默认值是 false
对象引用
Java 对对象的引用分为强引用、软引用、弱引用、虚引用四种,这些引用在 GC 时的处理策略不同
强引用不会被 GC 回收
软引用内存空间不足时会被 GC 回收
弱引用则在每次 GC 时被回收
虚引用必须和引用队列联合使用,主要用于跟踪一个对象被垃圾回收的过程
异常机制
Java 的异常处理机制就是 try-catch-finally 机制
所有的异常都有一个共同的祖先 Throwable(可抛出)
Throwable有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。异常和错误的区别是:异常能被程序本身可以处理,错误是无法处理
版本差异
Java 的 1.8 版本是一个长期支持的版本,1.11 版本也是一个长期支持的版本,1.11 版本中已经包含了 1.9、1.10 版本的功能。
在 1.8 版本中 Java 增加了对 lambda 表达式的支持,使 Java 代码的编写可以更简洁,也更方便支持并行计算。并且提供了很多 Stream 流式处理的 API。1.8 版本还支持了方法引用的能力,可以进一步简化 lambda 表达式的写法。
在 1.8 版本中,接口可以提供默认方法了,这样可以简化一些简单的抽象类。最后在 1.8 版本中对方法区进行调整,使用 Metaspace 替换掉了 PermGen 的永久代。Metaspace 与 PermGen 之间最大的区别在于:Metaspace 并不在虚拟机中,而是使用本地内存。替换的目的一方面是可以提升对元数据的管理同时提升 GC 效率,另一方面是方便后续 HotSpot 与 JRockit 合并。
在 1.9、1.10 版本中的主要特性是增加了模块系统,将 G1 设为默认垃圾回收器、支持局部变量推断等功能。这些功能都已经包含在 1.11 版本中。
1.11 版本中提供的最激动人心的功能是 ZGC 这个新的垃圾回收器,ZGC 为大内存堆设计,有着非常强悍的性能,能够实现 10ms 以下的 GC 暂停时间。1.11 版本对字符串处理 API 进行了增强,提供了字符复制等功能。1.11 版本还内置了 HttpClient。
浙公网安备 33010602011771号