java.util.concurrent.locks.LockSupport 源码

LockSupport 主要利用了Unsafe类中提供的part和unpart两个方法.而LockSupport类暴露出来的两个核心接口也是part和unpart两个.

相关类图:

java.util.concurrent.locks.LockSupport源码:

package java.util.concurrent.locks;

import sun.misc.Unsafe;

public class LockSupport {
    //构造方法私有化
    private LockSupport() {}

    //把Thread实例t的parkBlocker字段的值设置为arg
    private static void setBlocker(Thread t, Object arg) {
        UNSAFE.putObject(t, parkBlockerOffset, arg);
    }

    //获取对象t中parkBlocker字段的值
    public static Object getBlocker(Thread t) {
        if (t == null)
            throw new NullPointerException();
        return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
    }

    //取消阻塞线程,如果线程已经处于非阻塞状态,那么下次调用park时不会阻塞线程
    public static void unpark(Thread thread) {
        if (thread != null)//判断是否为空,然后调用unsafe的unpark
            UNSAFE.unpark(thread);
    }

    // 使当前调用线程在给定对象上阻塞(不能保证一定阻塞,
    // 因为如果之前在非阻塞状态调用了unpark 方法的话,此次调用park方法就不会阻塞线程)
    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);在调用park阻塞当前线程之前,先记录当前线程的blocker
        UNSAFE.park(false, 0L);//调用park阻塞当前线程
        setBlocker(t, null);//当线程可以继续执行下去时,再将parkBlocker设置为null
    }

    // 使当前线程在blocker对象上阻塞给定的纳秒时间
    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);
        }
    }

    // 使当前线程在blocker对象上阻塞到给定的时间点
    // 这个时间点是从Epoch time(1970-01-01 00:00:00 UTC)开始算起的某个具体的时间点
    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);
    }

    // 使当前线程在blocker对象上阻塞到给定的时间点
    // 这个时间点是从Epoch time(1970-01-01 00:00:00 UTC)开始算起的某个具体的时间点
    public static void parkUntil(long deadline) {
        UNSAFE.park(true, deadline);
    }

    //返回伪随机初始化或更新的二级种子
    static final int nextSecondarySeed() {
        int r;
        Thread t = Thread.currentThread();
        if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
            r ^= r << 13;   // xorshift
            r ^= r >>> 17;
            r ^= r << 5;
        }
        else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
            r = 1; // avoid zero
        UNSAFE.putInt(t, SECONDARY, r);
        return r;
    }

    //引用Unsafe类
    private static final sun.misc.Unsafe UNSAFE;
    //Thread类中parkBlocker字段的偏移量
    private static final long parkBlockerOffset;
    //Thread 类中threadLocalRandomSeed字段的偏移量
    private static final long SEED;
    //Thread 类中threadLocalRandomProbe字段的偏移量
    private static final long PROBE;
    //Thread 类中threadLocalRandomSecondarySeed字段的偏移量
    private static final long SECONDARY;

    //初始化上面4个字段的值
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
            SEED = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSeed"));
            PROBE = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomProbe"));
            SECONDARY = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
        } catch (Exception ex) { throw new Error(ex); }
    }

}

 

类 LockSupport

java.util.concurrent.locks.LockSupport extends Object

    用来创建锁和其他同步类的基本线程阻塞原语。

    此类以及每个使用它的线程与一个许可关联(从 Semaphore 类的意义上说)。如果该许可可用,并且可在进程中使用,则调用 park 将立即返回;否则可能 阻塞。如果许可尚不可用,则可以调用 unpark 使其可用。(但与 Semaphore 不同的是,许可不能累积,并且最多只能有一个许可。)

    park 和 unpark 方法提供了阻塞和解除阻塞线程的有效方法,并且不会遇到导致过时方法 Thread.suspend 和 Thread.resume 因为以下目的变得不可用的问题:由于许可的存在,调用 park 的线程和另一个试图将其 unpark 的线程之间的竞争将保持活性。此外,如果调用者线程被中断,并且支持超时,则 park 将返回。park 方法还可以在其他任何时间“毫无理由”地返回,因此通常必须在重新检查返回条件的循环里调用此方法。从这个意义上说,park 是“忙碌等待”的一种优化,它不会浪费这么多的时间进行自旋,但是必须将它与 unpark 配对使用才更高效。

    三种形式的 park 还各自支持一个 blocker 对象参数。此对象在线程受阻塞时被记录,以允许监视工具和诊断工具确定线程受阻塞的原因。(这样的工具可以使用方法 getBlocker(java.lang.Thread) 访问 blocker。)建议最好使用这些形式,而不是不带此参数的原始形式。在锁实现中提供的作为 blocker 的普通参数是 this

    这些方法被设计用来作为创建高级同步实用工具的工具,对于大多数并发控制应用程序而言,它们本身并不是很有用。park 方法仅设计用于以下形式的构造:

while (!canProceed()){
  ...
  LockSupport.park(this);
}

    在这里,在调用 park 之前, canProceed 和其他任何动作都不会锁定或阻塞。因为每个线程只与一个许可关联, park 的任何中间使用都可能干扰其预期效果。

    示例用法。 以下是一个先进先出 (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。

  1. 将当前调用lock的线程加入队列
  2. 如果等待队列的队首元素不是当前线程或者locked为true,则说明有线程已经持有了锁,那么调用park阻塞其余的线程。
  3. 如果队首元素是当前线程且locked为false,则说明前面已经没有人持有锁,删除队首元素也就是当前的线程,然后当前线程继续正常执行。
  4. 执行完后调用unlock方法将锁变量修改为false,并解除队首线程的阻塞状态。此时的队首元素继续之前的判断。

 

方法摘要

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) 
          如果给定线程的许可尚不可用,则使其可用。

 

unpark

public static void unpark(Thread thread)

    如果给定线程的许可尚不可用,则使其可用。如果线程在 park 上受阻塞,则它将解除其阻塞状态。否则,保证下一次调用 park 不会受阻塞。如果给定线程尚未启动,则无法保证此操作有任何效果。

    参数:

    thread - 要执行 unpark 操作的线程;该参数为 null 表示此操作没有任何效果。

 

park

public static void park(Object blocker)

    为了线程调度,在许可可用之前禁用当前线程。

    如果许可可用,则使用该许可,并且该调用立即返回;否则,为线程调度禁用当前线程,并在发生以下三种情况之一前,使其处于休眠状态:

  • 其他某个线程调用将当前线程作为目标调用 unpark;或者
  • 其他某个线程中断当前线程;或者
  • 该调用不合逻辑地(即毫无理由地)返回。

    此方法不报告是哪个线程导致该方法返回。调用者应该重新检查最先导致线程暂停的条件。调用者还可以确定返回时该线程的中断状态。

    参数:

    blocker - 导致此线程暂停的同步对象

 

parkNanos

public static void parkNanos(Object blocker,long nanos)

    为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。

    如果许可可用,则使用该许可,并且该调用立即返回;否则,为线程调度禁用当前线程,并在发生以下四种情况之一前,使其处于休眠状态:

  • 其他某个线程将当前线程作为目标调用 unpark;或者
  • 其他某个线程中断当前线程;或者
  • 已超过指定的等待时间;或者
  • 该调用不合逻辑地(即毫无理由地)返回。

    此方法不报告是哪个线程导致该方法返回。调用者应该重新检查最先导致线程暂停的条件。调用者还可以确定返回时该线程的中断状态或已过的时间。

参数:

    blocker - 导致此线程暂停的同步对象

    nanos - 要等待的最大毫秒数

 

parkUntil

public static void parkUntil(Object blocker, long deadline)

    为了线程调度,在指定的时限前禁用当前线程,除非许可可用。

    如果许可可用,则使用该许可,并且该调用立即返回;否则,为线程调度禁用当前线程,并在发生以下四种情况之一前,使其处于休眠状态:

  • 其他某个线程将当前线程作为目标调用 unpark;或者
  • 其他某个线程中断当前线程;或者
  • 指定时限已过;或者
  • 该调用不合逻辑地(即毫无理由地)返回。

    此方法不报告是哪个线程导致该方法返回。调用者应该重新检查最先导致线程暂停的条件。调用者还可以确定返回时该线程的中断状态或当前时间。

    参数:

    blocker - 导致此线程暂停的同步对象

    deadline - 要等待的绝对时间,用相对于历元 (Epoch) 的毫秒数值表示

 

getBlocker

public static Object getBlocker(Thread t)

    返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。返回的值只是一个瞬间快照,即由于未解除阻塞或者在不同的 blocker 对象上受阻而具有的线程。

 

park

public static void park()

    为了线程调度,禁用当前线程,除非许可可用。

    如果许可可用,则使用该许可,并且该调用立即返回;调用park后有以下三种情况,能使线程继续执行下去,否则就休眠:

  • 其他某个线程将当前线程作为目标调用 unpark;或者
  • 其他某个线程中断当前线程;或者
  • 该调用不合逻辑地(即毫无理由地)返回。

    此方法并不报告是哪个线程导致该方法返回。调用者应该重新检查最先导致线程暂停的条件。调用者还可以确定线程返回时的中断状态。

 

parkNanos

public static void parkNanos(long nanos)

    为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。

    如果许可可用,则使用该许可,并且该调用立即返回;否则,为线程调度禁用当前线程,并在发生以下四种情况之一以前,将其处于休眠状态:

  • 其他某个线程将当前线程作为目标调用 unpark;或者
  • 其他某个线程中断当前线程;或者
  • 已超过指定的等待时间;或者
  • 该调用不合逻辑地(即无缘无故地)返回。

    此方法并不报告是哪个线程导致该方法返回。调用者应该重新检查最先导致线程暂停的条件。调用者还可以确定线程返回时的中断状态或所用的时间。

    参数:

    nanos - 要等待的最大毫秒数

parkUntil

public static void parkUntil(long deadline)

    为了线程调度,在指定的时限前禁用当前线程,除非许可可用。

    如果许可可用,则使用该许可,并且调用立即返回;否则,为线程调度禁用当前线程,并在发生以下四种情况之一以前,将其处于休眠状态:

  • 其他某个线程将当前线程作为目标调用 unpark;或者
  • 其他某个线程中断当前线程;或者
  • 指定的最后期限已过;或者
  • 该调用不合逻辑地(即毫无理由地)返回。

    此方法并不报告是哪个线程导致该方法返回。调用者应该重新检查最先导致线程暂停的条件。调用者还可以确定线程返回时的中断状态或当前时间。

    参数:

    deadline - 要等待的绝对时间,用相对于历元的毫秒数值表示

转载于:https://my.oschina.net/langwanghuangshifu/blog/2877289

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值