Java
Java多线程
Java并发
JUC锁

Java多线程 19 - LockSupport

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

1. LockSupport介绍

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。LockSupport中的park()unpark()的作用分别是阻塞线程和解除阻塞线程,而且park()unpark()不会遇到Thread.suspend()Thread.resume()所可能引发的死锁问题,因为park()unpark()有许可的存在;调用park()的线程和另一个试图将其unpark()的线程之间的竞争将保持活性。

LockSupport函数列表

  • // 返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null
  • static Object getBlocker(Thread t)
  • // 为了线程调度,禁用当前线程,除非许可可用
  • 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)

2. LockSupport源码

下面是LockSupport的源码,基于JDK1.7.0_07:

  • package java.util.concurrent.locks;
  • import sun.misc.Unsafe;
  • public class LockSupport {
  • private LockSupport() {} // Cannot be instantiated.
  • private static void setBlocker(Thread t, Object arg) {
  • // Even though volatile, hotspot doesn't need a write barrier here.
  • UNSAFE.putObject(t, parkBlockerOffset, arg);
  • }
  • public static void unpark(Thread thread) {
  • if (thread != null)
  • UNSAFE.unpark(thread);
  • }
  • public static void park(Object blocker) {
  • Thread t = Thread.currentThread();
  • setBlocker(t, blocker);
  • UNSAFE.park(false, 0L);
  • setBlocker(t, null);
  • }
  • 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);
  • }
  • }
  • public static void parkUntil(Object blocker, long deadline) {
  • Thread t = Thread.currentThread();
  • setBlocker(t, blocker);
  • UNSAFE.park(true, deadline);
  • setBlocker(t, null);
  • }
  • public static Object getBlocker(Thread t) {
  • if (t == null)
  • throw new NullPointerException();
  • return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
  • }
  • public static void park() {
  • UNSAFE.park(false, 0L);
  • }
  • public static void parkNanos(long nanos) {
  • if (nanos > 0)
  • UNSAFE.park(false, nanos);
  • }
  • 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;
  • }
  • // Hotspot implementation via intrinsics API
  • 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);
  • }
  • }
  • }

从上面的源码可以得知,LockSupport是通过调用Unsafe函数中的接口实现阻塞和解除阻塞的。

3. LockSupport示例

下面的LockSupport示例比较简单,在主线程中使用LockSupport挂起主线程,然后在子线程中使用LockSupport将主线程唤醒:

  • package com.coderap.juc.lock;
  • import java.util.concurrent.locks.LockSupport;
  • public class LockSupportTest {
  • public static void main(String[] args) {
  • // 主线程
  • Thread mainThread = Thread.currentThread();
  • // 子线程
  • Thread thread = new Thread(new Runnable() {
  • @Override
  • public void run() {
  • try {
  • // 先休眠3秒
  • System.out.println(System.currentTimeMillis() + ": " + Thread.currentThread().getName() + " start sleep");
  • Thread.sleep(3000);
  • System.out.println(System.currentTimeMillis() + ": " + Thread.currentThread().getName() + " end sleep");
  • } catch (InterruptedException e) {
  • e.printStackTrace();
  • }
  • System.out.println(System.currentTimeMillis() + ": " + "LockSupport unpark Main Thread");
  • // 唤醒主线程
  • LockSupport.unpark(mainThread);
  • // 对主线程执行中断操作,也会唤醒主线程
  • // mainThread.interrupt();
  • }
  • }, "Thread - 1");
  • System.out.println(System.currentTimeMillis() + ": " + Thread.currentThread().getName() + " start execute");
  • System.out.println(System.currentTimeMillis() + ": " + Thread.currentThread().getName() + " start Thread - 1");
  • // 启动子线程
  • thread.start();
  • System.out.println(System.currentTimeMillis() + ": " + "LockSupport park Thread: " + Thread.currentThread().getName());
  • // 挂起主线程
  • LockSupport.park();
  • System.out.println(System.currentTimeMillis() + ": " + Thread.currentThread().getName() + " continue execute");
  • System.out.println(System.currentTimeMillis() + ": " + Thread.currentThread().getName() + " interrupted: " + Thread.interrupted());
  • System.out.println(System.currentTimeMillis() + ": " + Thread.currentThread().getName() + " isInterrupted: " + Thread.currentThread().isInterrupted());
  • }
  • }

运行结果如下:

  • 1623833340841: main start execute
  • 1623833340842: main start Thread - 1
  • 1623833340842: LockSupport park Thread: main
  • 1623833340847: Thread - 1 start sleep
  • 1623833343856: Thread - 1 end sleep
  • 1623833343856: LockSupport unpark Main Thread
  • 1623833343856: main continue execute
  • 1623833343856: main interrupted: false
  • 1623833343856: main isInterrupted: false