jdk源码之LockSupport
前言/背景
在前面说到了UnSafe类,它给我提供了一个“后门”,让我们可以直接操作内存,挂起线程等操作。这一讲我们来看看LockSupport,顾名思义,它是给我们后面的LockSupport提供支持的。
概述
在我们过去的学习的,说起线程的挂起与恢复,我们就会想到wait与notify。在LockSupport中提供了另一个挂起(park)与恢复unpark线程的方式。两者的区别如下
- 语义上更符合。wait需要在sychronized代码中才能调用,首先要获得对象的监视锁,即面向对象操作的挂起与恢复;而park是面向线程操作的挂起与恢复。
- 使用上更灵活。wait操作我们需要先获取对象的监视锁;而park不需要,可以随意进行park与unpark,unpark可以先于park调用。
- interupt中断不同。wait时如果收到中断会抛出中断异常,我们可以在catch处理;park的话,我们可以通过interrupted或isInterrupted去判断线程是否中断。
park函数消耗一个许可,unpark函数提供一个许可。注意的是unpark连续提供多个许可,假如线程A通过unpark难线程B提供了一个许可,线程B调用park时会消耗这个许可,不会阻塞,可如果再调用时就会阻塞了。
源码/知识点
- 属性
//unsafe类的引用
private static final Unsafe UNSAFE;
//下面几个都是相应的内存偏移地址,,这个偏移量比较重要,我们可以设置,表示线程被谁阻塞的,我们可以线程分析工具方便地定位原因。 private static final long parkBlockerOffset; private static final long SEED; private static final long PROBE; private static final long SECONDARY;
- 静态代码块
static { try { // 获取Unsafe实例 UNSAFE = sun.misc.Unsafe.getUnsafe(); // 线程类类型 Class<?> tk = Thread.class; // 获取Thread的parkBlocker字段的内存偏移地址 parkBlockerOffset = UNSAFE.objectFieldOffset (tk.getDeclaredField("parkBlocker")); // 获取Thread的threadLocalRandomSeed字段的内存偏移地址 SEED = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomSeed")); // 获取Thread的threadLocalRandomProbe字段的内存偏移地址 PROBE = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomProbe")); // 获取Thread的threadLocalRandomSecondarySeed字段的内存偏移地址 SECONDARY = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomSecondarySeed")); } catch (Exception ex) { throw new Error(ex); } }
总结
在我们的开发中不会直接使用到这个类,但在AQS、并发原子类,以及netty,kafaka底层实现中,都有这个类,所以了解学习这个开“后门”的类还是很有必要的。
参考链接
- https://blog.csdn.net/opensure/article/details/53349698
- https://www.cnblogs.com/leesf456/p/5347293.html(Lock源码分析)