LockSupport概览

Dear 丶 2021-06-24 16:12 596阅读 0赞

https://www.cnblogs.com/lscz3633/p/7605427.html

Basic thread blocking primitives for creating locks and other synchronization classes.用来创建锁及其他同步类的基础线程阻塞原语。这是java doc中的解释,以下是一个先进先出 (first-in-first-out) 非重入锁类的框架。

  1. class FIFOMutex {
  2. private final AtomicBoolean locked = new AtomicBoolean(false); //原子
  3. private final Queue<Thread> waiters //并发库中的链式队列保存线程
  4. = new ConcurrentLinkedQueue<Thread>();
  5. public void lock() { //
  6. boolean wasInterrupted = false;
  7. Thread current = Thread.currentThread();
  8. waiters.add(current);
  9. // Block while not first in queue or cannot acquire lock
  10. while (waiters.peek() != current ||
  11. !locked.compareAndSet(false, true)) {//无法获取锁,则阻塞当前线程
  12. LockSupport.park(this);
  13. if (Thread.interrupted()) // ignore interrupts while waiting
  14. wasInterrupted = true;
  15. }
  16. waiters.remove();
  17. if (wasInterrupted) // reassert interrupt status on exit
  18. current.interrupt();
  19. }
  20. public void unlock() {
  21. locked.set(false);
  22. LockSupport.unpark(waiters.peek());
  23. }  

上述代码简单实现的锁功能,主要使用了LockSupport的park和unpark阻塞和释放线程,AtomicBoolean的CAS操作来判断是否持有锁ConcurrentLinkedQueue来保存等待线程,此队列是一个线程安全的队列,当前仅当线程在等待队列队首且持有锁才会跳出while循环,从等待队列中移除。

  1. locked.compareAndSet(false, true)的语意为,期望AtomicBoolean对象的值为false,并设置值为true,可以做为是否持有锁的判断

LockSupport源码







































方法摘要
static Object getBlocker(Thread t) 
          返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。
static void park() 
          为了线程调度,禁用当前线程,除非许可可用。
static void park(Object blocker) 
          为了线程调度,在许可可用之前禁用当前线程。
static void parkNanos(long nanos) 
          为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。
static void parkNanos(Object blocker, long nanos) 
          为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。
static void parkUntil(long deadline) 
          为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
static void parkUntil(Object blocker, long deadline) 
          为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
static void unpark(Thread thread) 
          如果给定线程的许可尚不可用,则使其可用。

LockSupport提供的全部为static修饰的静态方法,作为一个工具类在使用。主要提供了阻塞线程,和解除阻塞线程的方法。

  1. // Hotspot implementation via intrinsics API
  2. private static final Unsafe unsafe = Unsafe.getUnsafe(); //持有一个Unsafe的实例
  3. private static final long parkBlockerOffset; //偏移量
  4. static {
  5. try {
  6. parkBlockerOffset = unsafe.objectFieldOffset //初始化获取属性偏移量
  7. (java.lang.Thread.class.getDeclaredField("parkBlocker"));
  8. } catch (Exception ex) { throw new Error(ex); }
  9. }

 

上一章中我们探讨过unsafe 的CAS用法,这里同样,LockSupport采用Unsafe类来获取属性修改属性,而且parkBlocker是Thread类的成员变量

  1. /**
  2. * The argument supplied to the current call to
  3. * java.util.concurrent.locks.LockSupport.park.
  4. * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
  5. * Accessed using java.util.concurrent.locks.LockSupport.getBlocker
  6. */
  7. volatile Object parkBlocker;

同样是volatile修饰,意为阻塞者,阻塞当前线程的 对象,这个属性为我们提供了可以监控线程被阻塞的信息方法。

  1. private static void setBlocker(Thread t, Object arg) {
  2. // Even though volatile, hotspot doesn't need a write barrier here.
  3. unsafe.putObject(t, parkBlockerOffset, arg);
  4. }
  5. /**
  6. * Returns the blocker object supplied to the most recent
  7. * invocation of a park method that has not yet unblocked, or null
  8. * if not blocked. The value returned is just a momentary
  9. * snapshot -- the thread may have since unblocked or blocked on a
  10. * different blocker object.
  11. *
  12. * @param t the thread
  13. * @return the blocker
  14. * @throws NullPointerException if argument is null
  15. * @since 1.6
  16. */
  17. public static Object getBlocker(Thread t) {
  18. if (t == null)
  19. throw new NullPointerException();
  20. return unsafe.getObjectVolatile(t, parkBlockerOffset);//根据属性偏移量获取属性值
  21. }

  为什么通过unsafe来获取线程的parkBlocker变量,而不是通过set和get方法获取?这是因为parkBlocker只有在线程被阻塞时才有意义,而此时set和get方法是无法通过线程对象调用的。

  1. public native Object getObjectVolatile(Object var1, long var2);
  2. public native void putObjectVolatile(Object var1, long var2, Object var4);//var2 为属性在var1中的偏移量,var4为要设置的属性值

这是Unsafe类提供的native方法,具体实现在这里不再深究。

  1. 上面探索了LockSupport中对阻塞者信息的处理,下面来看下阻塞及解除阻塞函数。
  2. public static void park(Object blocker) {
  3. Thread t = Thread.currentThread(); //当前线程
  4. setBlocker(t, blocker); //设置被谁阻塞
  5. unsafe.park(false, 0L); //阻塞线程
  6. setBlocker(t, null); //线程解除阻塞,清空blocker信息
  7. }
  8. public static void unpark(Thread thread) {
  9. if (thread != null)
  10. unsafe.unpark(thread); //解除线程阻塞
  11. }

  这是Unsafe类中实质阻塞线程及解除线程阻塞的native函数,var1指明时间为绝对时间还是相对时间,false为相对时间,var2意为解除阻塞时间,设置为0则只有当线程中断,或调用unpark函数时解除锁定,若不为0,则等待var2时间后也会自动解除阻塞,注意这里的时间单位为纳秒;当var1位true时,为绝对时间,var2的时间单位为毫秒

  1. public native void unpark(Object var1);
  2. public native void park(boolean var1, long var2);

  最多等待nanos纳秒

  1. public static void parkNanos(Object blocker, long nanos) {
  2. if (nanos > 0) {
  3. Thread t = Thread.currentThread();
  4. setBlocker(t, blocker);
  5. unsafe.park(false, nanos);
  6. setBlocker(t, null);
  7. }
  8. }

发表评论

表情:
评论列表 (有 0 条评论,596人围观)

还没有评论,来说两句吧...

相关阅读

    相关 LockSupport

    LockSupport是一个线程工具类,所有的方法都是静态方法。 可以让线程执行到指定位置阻塞(相当于线程中wait) park,在任意位置唤醒由其他线程中唤醒(notify

    相关 LockSupport介绍

    可重入锁又名递归锁 是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提:锁对象是同一个对象),不会因为之前已经获取过还没释放而阻塞. Java

    相关 LockSupport工具

    当需要阻塞或唤醒一个线程的时候,都会使用LockSupport工具类来完成相应工作。LockSupport定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功

    相关 LockSupport详解

    LockSupport是一个编程工具类,主要是为了阻塞和唤醒线程用的。使用它我们可以实现很多功能,今天主要就是对这个工具类的讲解,希望对你有帮助: 一、LockSupport

    相关 LockSupport

    LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,当然阻塞之后肯定得有唤醒的方法。 主要有两类方法:park和unpark。