LockSupport概览

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) 非重入锁类的框架。

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的park和unpark阻塞和释放线程,AtomicBoolean的CAS操作来判断是否持有锁ConcurrentLinkedQueue来保存等待线程,此队列是一个线程安全的队列,当前仅当线程在等待队列队首且持有锁才会跳出while循环,从等待队列中移除。

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

 

LockSupport源码

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

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

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

 

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

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

 

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

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

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

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

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

      上面探索了LockSupport中对阻塞者信息的处理,下面来看下阻塞及解除阻塞函数。

 

public static void park(Object blocker) {
    Thread t = Thread.currentThread(); //当前线程
    setBlocker(t, blocker); //设置被谁阻塞
    unsafe.park(false, 0L);  //阻塞线程
    setBlocker(t, null);  //线程解除阻塞,清空blocker信息
}
 
public static void unpark(Thread thread) {
    if (thread != null)
        unsafe.unpark(thread);   //解除线程阻塞
}

 

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

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

  最多等待nanos纳秒

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);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值