JUC源码分析5-locks-LockSupport
来源:互联网 发布:财务软件 知乎 编辑:程序博客网 时间:2024/04/28 12:42
LockSupport通过unsafe提供阻塞和唤醒线程的方法,AQS和其他的lock都会使用到这个基础类。
private LockSupport() {} // Cannot be instantiated.private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long parkBlockerOffset;static { try { parkBlockerOffset = unsafe.objectFieldOffset (java.lang.Thread.class.getDeclaredField("parkBlocker")); } catch (Exception ex) { throw new Error(ex); }}
每个线程都有一个volatile Object parkBlocker;字段,用于设置阻塞时,是被那个线程阻塞,可用于监控线程。LockSupport也提供设置和获取parkBlocker方法:
private static void setBlocker(Thread t, Object arg) { // Even though volatile, hotspot doesn't need a write barrier here. unsafe.putObject(t, parkBlockerOffset, arg);}public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); return unsafe.getObjectVolatile(t, parkBlockerOffset);}
LockSupport通过底层unsafe提供park,unpark操作。简单点说:底层维护一个二义性的_counter来保存一个许可,需要注意的是这个许可是一次性的,unpark操作设置该值为1,park操作检查该值是否为1,为1直接返回,不为1,则阻塞。
考虑下面几种情况是为什么:
1.unpark->park,unpark释放一个许可,park直接返回,不阻塞;
2.unpark->park->park,unpark释放一个许可,2次park阻塞;
3.park->unpark->unpark,park阻塞后多次unpark,unpark修改_counter为1,多次调用也无所谓,为什么单独提出这个,是因为在AQS共享模式下,获取锁后,需要通知所有等待锁的线程,会从阻塞队列中删除/唤醒头结点使用for循环,我感觉有可能多次unpark操作(个人想法,不一定完全正确,谁了解的可以解释下)。
如果使用wait/notify来实现同步,notify在wait之前执行,wait会一直阻塞,就会出问题了。
带blocker参数和不带blocker参数:
public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); unsafe.park(false, 0L); setBlocker(t, null);}public static void parkNanos(Object blocker, long nanos) { if (nanos > 0) { Thread t = Thread.currentThread(); setBlocker(t, blocker); unsafe.park(false, nanos); setBlocker(t, null); }}public static void parkUntil(Object blocker, long deadline) { Thread t = Thread.currentThread(); setBlocker(t, blocker); unsafe.park(true, deadline); setBlocker(t, null);}public static void park() { unsafe.park(false, 0L);}public static void parkNanos(long nanos) { if (nanos > 0) unsafe.park(false, nanos);}public static void parkUntil(long deadline) { unsafe.park(true, deadline);}
LockSupport的javadoc说明在3中情况下回立即返回:
1.有其他线程调用了本线程的unpark操作;
2.其他线程中断了本线程
3.The call spuriously (that is, for no reason) returns.
除了上面3种情况,底层Unsafe的public native void park(boolean flag, long l);下面情况也会唤醒:
1.flag为true,传入的dealline到了
2.flag为false,传入的park时间time到了
unpark操作唤醒后,线程调度就由各个平台自己控制:
<span style="font-size:18px;">public static void unpark(Thread thread) { if (thread != null) unsafe.unpark(thread);}</span>
参考:
http://blog.csdn.net/hengyunabc/article/details/28126139
http://www.360doc.com/content/14/0812/22/1073512_401408738.shtml
- JUC源码分析5-locks-LockSupport
- JUC源码分析8-locks-AQS-condition
- JUC源码分析9-locks-ReentrantLock
- JUC源码分析10-locks-CountDownLatch
- JUC源码分析11-locks-Semaphore
- JUC源码分析12-locks-CyclicBarrier
- JUC源码分析13-locks-ReentrantReadWriteLock
- JUC源码分析6-locks-AQS-独占模式
- JUC源码分析7-locks-AQS-共享模式
- LockSupport源码分析
- JUC源码解析(6)-locks-AbstractQueuedSynchronizer
- LockSupport源码分析(JDK 1.7)
- LockSupport的源码分析(上)
- LockSupport的源码分析(中)
- 03.JUC 锁 - LockSupport
- JUC - Semaphore 源码分析
- JUC - CountDownLatch 源码分析
- JUC - ReentrantLock 源码分析
- 全国所有省份、城市的JSON
- Ubuntu查找软件安装位置
- Genymotion 启动报错
- 静态 注册的Broadcast Receiver怎么向Activity传递数据
- linux 删除共享内存段
- JUC源码分析5-locks-LockSupport
- php使用json_decode返回NULL
- ExtJS -- QuickTip grid设置鼠标移动到行时提示第一列的信息
- 国内技术团队博客
- Leetcode no. 90
- 7walker闪屏
- PullToRefresh上拉加载,下拉刷新
- 347. Top K Frequent Elements (C++程序实现,两种方案)
- C# ListView 编写 ListView 实体类