我学JUC之LockSupport
来源:互联网 发布:2017网络事件 编辑:程序博客网 时间:2024/06/06 03:13
LockSupport是基本的线程阻塞原语, 用于构建lock和其他同步类.
这个类将每个线程与一个permit进行关联(类似于java.util.concurrent.Semaphore一样的感觉). 如果permit可用的话, 调用park方法会消费掉permit, 然后直接返回. 否则, 会阻塞线程. 调用unpark会使得不可用的permit可用.(和Semaphore不同的是, permit不会累加, 每个线程最多只有一个permit).
因为使用了permit, park和unpark方法提供了有效的block和unblock线程的方法. 与已经废弃的Thread.suspend和Thread.resume方法不同. 线程A调用park, 另一个线程B调用unpark来unblock A, 这两者发生竞争, 仍然会使得线程A保持活性.
另外, 如果调用者线程被interrupted, park会返回, 同时park也有timeout支持. park方法可能会随时无原因的返回, 所以一般调用需要在一个检测condition是否可用的循环中使用. 在这个意义上, park可以当作是一个busy wait, 而不需要太多时间自旋.
三种形式的park都支持传入blocker参数. 这个对象在线程被阻塞等待permit时被记录下来, 可用于监控和诊断工具来分析当前线程因为何种原因而阻塞(这些工具通过使用getBlocker(Thread)方法来获取). 推荐使用这种能够传入bolcker对象参数的方法类型. 在lock实现中, 通常传入的blocker参数是this
这些方法同样也被设计用于创建更高层次的同步工具.
park方法被设计只用于以下的形式:
while (!canProceed()) { ... LockSupport.park(this); }}
在上面的代码中, park方法之前的, 无论是canProceed或其他方法都不应该涉及locking或block. 因为每个线程只有一个permit, 任何中间形式的使用park都会干扰想要的效果.
下面是一个简单的FIFO非重入锁的实现.
class FIFOMutex { private final AtomicBoolean locked = new AtomicBoolean(false); private final Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>(); public void lock() { boolean wasInterrupted = false; Thread current = Thread.currentThread(); waiters.add(current); // Block while not first in queue or cannot acquire lock while (waiters.peek() != current || !locked.compareAndSet(false, true)) { LockSupport.park(this); if (Thread.interrupted()) // ignore interrupts while waiting wasInterrupted = true; } waiters.remove(); if (wasInterrupted) // reassert interrupt status on exit current.interrupt(); } public void unlock() { locked.set(false); LockSupport.unpark(waiters.peek()); } }
LockSupport的方法:
//使用一个线程thread的permit可用. 如果这个thread之前阻塞在park方法上, 那么会unblock. 或者thread没有阻塞在park方法上, 下一次park方法时, thread会直接返回, 而不会阻塞. 不能保证线程没有启动时有效.public static void unpark(Thread thread)/**禁止程被调度, 除非permit可用如果permit可用, 那么就会被直接消费, 然后park调用返回. 否则当前线程会被停止调度, 保持休眠状态直到以下三个条件之一发生:1. 另外一个线程对其调用了unpark2. 另外一个线程调用了Thread.interrupt(thread)方法, interrupt当前线程3. 毫无理由的返回这个方法并不会报告什么原因造成了返回, 调用者应该立即检查造成thread调用park的Condition, 同时, 调用者也可能需要检查thread的interrupt状态.**/public static void park(Object blocker)//说明与上相同, nanos是线程阻塞的最长的纳秒数public static void parkNanos(Object blocker, long nanos)//说明同上. deadline是线程要阻塞到的绝对时间, Epoch时间戳, 单位为毫秒public static void parkUntil(Object blocker, long deadline)public static void park()public static void parkNanos(long nanos)public static void parkUntil(long deadline)//获取某个Thread最近调用park时传入的blocker. 每次可能返回不同的值public static Object getBlocker(Thread t)//设置一个线程的blocker对象private static void setBlocker(Thread t, Object arg)
blocker的原理:
设置blocker时设置的是Thread的一个字段parkBlocker, 通过UNSAFE类来获取其在Thread类中的偏移, 然后通过UNSAFE类在这个偏移上放置blocker的指针就可以了.
static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); Class<?> tk = Thread.class; //通过UNSAFE类来获取Thread类中的parkBlocker在内存中在对象中的偏移 parkBlockerOffset = UNSAFE.objectFieldOffset (tk.getDeclaredField("parkBlocker")); ..... } catch (Exception ex) { throw new Error(ex); } } public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false, 0L); setBlocker(t, null); } private static void setBlocker(Thread t, Object arg) { //使用UNSAFE的方法在对象的相应偏移位置放置对象指针 UNSAFE.putObject(t, parkBlockerOffset, arg); }
- 我学JUC之LockSupport
- JUC锁-07之 LockSupport
- 03.JUC 锁 - LockSupport
- Java多线程系列--“JUC锁”07之 LockSupport
- Java多线程系列--“JUC锁”07之 LockSupport (r)
- 详解JUC之锁——LockSupport类(04)
- Java多线程系列--“JUC锁”07之 LockSupport
- Java多线程系列--“JUC锁”07之 LockSupport
- JUC源码分析5-locks-LockSupport
- Java并发编程札记-(四)JUC锁-06LockSupport
- LockSupport
- LockSupport
- LockSupport
- LockSupport
- LockSupport
- java并发编程之LockSupport
- Struts之我学
- Makefile之我学
- (转)二叉树算法引发的思考:指针参数传递、引用的陷阱
- SparkSQL 入门操作
- acdream1234(Simpson积分)
- java中类加载的全过程及内存图分析
- c3p0和QueryRunner的结合使用,让开发更加简便
- 我学JUC之LockSupport
- N皇后问题
- 【学习笔记】6.包含多个段的程序
- Java从入门到精通阅读笔记(第4版)11
- CCF201612-2
- 【C++数据结构】模板链栈
- 递归函数理解
- Hexo搭建博客以及多端同步更新
- Android移动应用开发学习笔记(二)——用户注册