源码解读——LockSupport类

作者: 打铁大师 | 来源:发表于2017-12-04 22:25 被阅读15次

LockSupport

LockSupport是一个线程阻塞工具,它可以在线程内任意位置让线程阻塞。

优点

  • 跟Thread.suspend()相比,它弥补了由于resume()发生在前,导致线程无法继续执行的情况。
  • 与Object.wait()相比,它不需要先获得某个对象的锁,也不会抛出InterruptedException异常。

特点

LockSupport为每个线程准备了一个许可,如果许可可用,那么park()函数会立即返回,并且消费这个许可(也就是将许可变得不可用),如果许可不可用,那么就会阻塞。而unpark()则使得一个许可变为可用(但是和信号量不同的是,许可不能累加,你不可能拥有超过一个许可,它永远只有一个)。

源码解读

public class LockSupport {
  // 这里用了private修饰,使得LockSupport无法被实例化,即不能使用new 操作费
  private LockSupport() {} 

 // 设置一个阻塞对象,用来标识当前线程在等待的对象,主要用来问题排查和系统监控。
  private static void setBlocker(Thread t, Object arg) {
      //UNSAFE.putObject 是java原始方法
      UNSAFE.putObject(t, parkBlockerOffset, arg);
  }

  //如果线程的许可是不可用的,那么就使得线程的许可可以用。
  // 如果线程因为park方法而阻塞,那么调用此方法,线程将会被唤醒。
  // 如果线程还没有启动,那么调用该方法不能保证能有什么效果。
  public static void unpark(Thread thread) {
      if (thread != null)
          UNSAFE.unpark(thread);
  }

 //在park()方法的基础上,增加了标识当前线程在等待的对象。
  public static void park(Object blocker) {
      Thread t = Thread.currentThread();
      setBlocker(t, blocker);
      UNSAFE.park(false, 0L);
      setBlocker(t, null);
  }
  //在parkNanos(long 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);
    }
}
// 在parkUntil(long deadline)方法的基础上,增加了标识当前线程在等待的对象。
public static void parkUntil(Object blocker, long deadline) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(true, deadline);
    setBlocker(t, null);
}
  // 如果park()方法造成当前线程阻塞,而该线程还没有被唤醒,那么返回传递给park()方法的阻塞对象。如果该线程没有被阻塞,那就返回null;
public static Object getBlocker(Thread t) {
    if (t == null)
        throw new NullPointerException();
    return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
}

   // 如果许可是可用的,那么许可会被消费,然后pack方法会立即返回。(unpark方法会使得许可可用)
   //作用阻塞当前线程,如果调用unpark(Thread thread)方法或者当前线程中断(不会抛出异常,只会默默的返回),才能从park方法返回。
public static void park() {
    UNSAFE.park(false, 0L);
}
   //  在park()的基础上增加了超时返回。
public static void parkNanos(long nanos) {
    if (nanos > 0)
        UNSAFE.park(false, nanos);
}
    // 在park()的基础上增加了到deadline时间返回。
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;
    UNSAFE.putInt(t, SECONDARY, r);
    return r;
}

// 通过内置API实现Hotspot
private static final sun.misc.Unsafe UNSAFE;
private static final long parkBlockerOffset;
private static final long SEED;
private static final long PROBE;
private static final long SECONDARY;

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

Demo1——LockSupport.getBlocker获取阻塞对象

public class LockSupportDemo1 {
  private static Object u = new Object();
  private static ChangeObjectThread t1 = new ChangeObjectThread("t1");

  private static class ChangeObjectThread extends Thread {
    public ChangeObjectThread(String name) {
        super.setName(name);
    }

    @Override
    public void run() {
            LockSupport.park(u);
    }
 }

   public static void main(String[] args) throws InterruptedException ,Exception{
     t1.start();
     Thread.sleep(100);
     System.out.println(LockSupport.getBlocker(t1));
     LockSupport.unpark(t1);
     t1.join();
     System.out.println(LockSupport.getBlocker(t1));
 }
}

结果如下:

java.lang.Object@2401f4c3
null

Demo1—— unpark方法在park方法之前调用

LockSupport.unpark()可以在LockSupport.park()方法前调用,不会造成线程阻塞,原因是,LockSupport.unpark方法之后,许可已可用,后面在调用LockSupport.park方法,LockSupport.park方法会直接返回。

  public class LockSupportDemo2 {
  private static Object u = new Object();
  private static ChangeObjectThread t1 = new ChangeObjectThread("t1");

  private static class ChangeObjectThread extends Thread {
      public ChangeObjectThread(String name) {
          super.setName(name);
      }

      @Override
      public void run() {
          try {
              Thread.currentThread().sleep(1000);
              System.out.println("park()方法被调用");
              LockSupport.park(u);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
  }

  public static void main(String[] args) throws InterruptedException, Exception {
      t1.start();
      LockSupport.unpark(t1);
      System.out.println("unpark()被调用");
      t1.join();
  }
}

结果如下:

unpark()被调用
park()方法被调用

相关文章

网友评论

    本文标题:源码解读——LockSupport类

    本文链接:https://www.haomeiwen.com/subject/jzrfixtx.html