
java.util.concurrent.locks.LockSupport 是 Java 并发编程中的一个非常有用的线程阻塞工具类,它包含可以阻塞和唤醒线程的方法。这个类是Java并发编程中的基础工具之一,通常用于构建锁或其他同步组件。LockSupport的所有方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法。
LockSupport中的park()和unpark()方法分别用于阻塞线程和解除线程的阻塞状态。调用park()方法后,当前线程会被挂起,直到它被其他线程通过unpark()方法唤醒,或者线程被中断,或者调用该方法的线程从调用park()方法开始已经过了一个不可预知的时间。需要注意的是,LockSupport不会释放任何锁资源,因此在调用park()之前应确保当前线程没有持有任何可能导致死锁的锁。
LockSupport实际上是对线程等待/通知机制(即Object类中的wait/notify/notifyAll方法)的一种改进和扩展。与传统的等待/通知机制相比,LockSupport提供了更精确的线程阻塞和唤醒控制,以及更好的可移植性和可维护性。此外,LockSupport还可以与Java的并发锁(如ReentrantLock)和条件变量(如Condition)等高级并发工具结合使用,以实现更复杂的线程同步和协作模式。
LockSupport提供了一种挂起和恢复线程的机制,通常与线程同步原语(如锁和条件)一起使用。但是,与 Object.wait() 和 Object.notify() 或 Object.notifyAll() 相比,LockSupport 提供了一种更灵活的线程挂起和恢复方法。
LockSupport.park()
unpark,线程被中断,或者调用该方法的线程从调用 park 方法开始已经过了一个不可预知的时间。java.util.concurrent.locks 包中的锁一起使用。LockSupport.unpark(Thread thread)
LockSupport.park() 挂起的线程才能被 unpark() 恢复。LockSupport 来挂起和恢复线程。这比使用内置的等待/通知机制更加灵活和高效。java.util.concurrent.locks 一起使用:这个包中的锁(如 ReentrantLock)和条件(如 Condition)通常与 LockSupport 一起使用来实现复杂的线程同步模式。LockSupport 来挂起线程,直到事件或条件满足。下面代码使用 LockSupport 来挂起和恢复线程:
import java.util.concurrent.locks.LockSupport;
public class LockSupportExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("线程开始运行...");
// 做一些工作...
System.out.println("线程挂起...");
LockSupport.park(); // 挂起线程
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程被中断...");
} else {
System.out.println("线程被恢复...");
}
// 继续执行其他任务...
});
thread.start();
// 让主线程睡眠一段时间,确保子线程已经挂起
Thread.sleep(2000);
System.out.println("尝试恢复线程...");
LockSupport.unpark(thread); // 恢复线程
// 让主线程再睡眠一段时间,确保子线程有机会执行完毕
Thread.sleep(2000);
}
}让线程等待和唤醒是并发编程中的常见需求。以下是三种常用的方法,分别是使用Object类的wait()/notify()/notifyAll()方法、使用Lock和Condition接口,以及使用LockSupport类的park()和unpark()方法。

Object类的wait()/notify()/notifyAll()方法这是Java中最早提供的线程等待和唤醒机制。wait()方法会使当前线程等待,直到其他线程调用同一个对象的notify()或notifyAll()方法。
public class WaitNotifyExample {
private static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("线程1等待");
lock.wait(); // 线程等待
System.out.println("线程1被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("线程2唤醒其他线程");
lock.notify(); // 唤醒等待的线程
}
});
thread1.start();
Thread.sleep(1000); // 确保thread1先执行
thread2.start();
}
}Lock和Condition接口java.util.concurrent.locks.Lock接口和它的实现类(如ReentrantLock)提供了比synchronized更灵活的锁机制。Condition接口与Lock一起使用,可以实现等待/通知模式。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockConditionExample {
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
lock.lock();
try {
System.out.println("线程1等待");
condition.await(); // 线程等待
System.out.println("线程1被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
Thread thread2 = new Thread(() -> {
lock.lock();
try {
System.out.println("线程2唤醒其他线程");
condition.signal(); // 唤醒等待的线程
} finally {
lock.unlock();
}
});
thread1.start();
Thread.sleep(1000); // 确保thread1先执行
thread2.start();
}
}LockSupport类的park()和unpark()方法LockSupport它可以在线程中的任何位置阻塞线程的执行。park()方法用于阻塞线程,unpark()方法用于解除线程的阻塞状态。
import java.util.concurrent.locks.LockSupport;
public class LockSupportExample {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
System.out.println("线程1开始运行");
LockSupport.park("等待唤醒"); // 线程等待
System.out.println("线程1被唤醒");
});
thread1.start();
Thread.sleep(1000); // 确保thread1先执行并等待
System.out.println("主线程唤醒线程1");
LockSupport.unpark(thread1); // 唤醒线程1
}
}在使用LockSupport.park()时,建议检查线程的中断状态,因为park()不会响应中断,除非显式地检查并处理中断。在实际应用中,可以将park()放在一个循环中,并在循环条件中检查中断状态。
实际上 LockSupport 类的实现非常简单,并且它的很多功能都是依赖于 JVM 的底层支持的。它的核心方法是 park 和 unpark,分别用于阻塞和解除阻塞线程。
下面是 LockSupport 类的一些关键部分的源码分析:
public class LockSupport {
private LockSupport() {} // Cannot be instantiated.
// Blocks until unparked, interrupted, or the caller spuriously returns.
public static void park() {
Unsafe.getUnsafe().park(false, 0L);
}
// Blocks until unparked, interrupted, the caller spuriously returns,
// or the deadline passes, whichever comes first.
public static void parkNanos(long nanos) {
if (nanos > 0)
Unsafe.getUnsafe().park(false, nanos);
}
// Blocks until unparked, interrupted, the caller spuriously returns,
// or approximately deadline milliseconds have passed, whichever comes first.
public static void parkUntil(long deadline) {
Unsafe.getUnsafe().park(true, deadline);
}
// Unblocks the thread blocked by park().
public static void unpark(Thread thread) {
if (thread != null)
Unsafe.getUnsafe().unpark(thread);
}
// Hotspot implementation of park/unpark may need some help to find
// threads blocked on the LockSupport objects created by this class.
// These methods are natively implemented in the JDK.
private static native void setBlocker(Thread t, Object arg);
private static native Object getBlocker(Thread t);
// Disables the current thread for thread scheduling purposes, for up to the
// specified waiting time, unless the `permit` is available.
// This method is designed to be used as a tool for creating higher-level
// synchronization utilities, and is not intended for general use.
// It supports a single permit, which is initially unavailable, and
// which becomes available when `unpark` is invoked, or if the caller
// spuriously returns.
// ... additional methods related to permit (not shown here)
}从上面的源码片段中,我们可以看到以下几点:
LockSupport 是一个工具类,不能被实例化(构造函数是私有的)。
park 方法和一个 unpark 方法。这些方法都是静态的,可以直接通过类名调用。
park 方法用于阻塞当前线程,直到它被 unpark,线程被中断,或者出现其他未指定的情况(即“spurious wakeup”,虽然在现代 JVM 中这种情况很少见)。
parkNanos 和 parkUntil 方法允许设置一个时间限制,在此时间之后线程会自动解除阻塞,即使没有被其他线程显式地 unpark。
unpark 方法用于解除指定线程的阻塞状态。如果线程没有被阻塞,或者由于某种原因已经解除阻塞,调用 unpark 不会有任何效果。
Unsafe 类来实现的,这是一个提供低级别、非安全、操作系统级别访问的类。Unsafe 类中的 park 和 unpark 方法是本地方法(通过 JNI 调用),它们直接与 JVM 的线程调度器交互。
setBlocker 和 getBlocker 方法是本地方法,用于在 JVM 内部跟踪由 LockSupport 阻塞的线程。这些方法通常不用于应用程序代码。
LockSupport.park() 挂起线程时,应该确保有一个明确的机制来恢复(通过 unpark())或中断线程,以避免线程永久挂起。LockSupport 不会释放任何锁资源,因此在调用 park() 之前应该确保线程没有持有任何可能导致死锁的锁。Object.wait() 和 Thread.sleep() 不同,LockSupport.park() 不会响应中断,除非你在调用 park() 之前或之后显式检查中断状态。但是,如果线程在 park() 期间被中断,那么从 park() 返回后,中断状态将被清除(设置为 false),除非你在此之前调用了 Thread.interrupted() 来检查并清除中断状态。因此,通常建议在调用 park() 的循环中检查中断状态。LockSupport 的一些常见面试题LockSupport.park() 和 Thread.sleep() 有什么区别?答案:
LockSupport.park():它会暂停当前线程的执行,直到它被 unpark,线程被中断,或者出现虚假唤醒(spurious wakeup,但在现代JVM中很少见)。park 不需要处理 InterruptedException,并且它不会保持任何锁。Thread.sleep():它会使当前线程休眠指定的时间,时间到了之后线程会变为就绪状态。sleep 期间线程不会释放任何锁,而且必须处理 InterruptedException。LockSupport 的主要用途是什么?答案:
LockSupport 主要用于创建锁和其他同步工具的基础类。它提供了一种机制,允许线程等待某个条件成立,而不需要轮询。这种等待是通过 park 和 unpark 方法来实现的,它们是构建高效锁和其他同步工具的关键。
LockSupport.park() 为什么比传统的线程等待方式更高效?答案:
传统的线程等待方式通常涉及到轮询(polling)或者使用 Thread.sleep(),这些方法都会浪费CPU资源,因为它们要么不断地检查条件,要么使线程进入睡眠状态,而在条件可能变为真时不会立即唤醒。LockSupport.park() 提供了一种更有效的方式,它允许线程在条件不满足时进入无消耗等待状态,直到它被 unpark 或中断,这样可以减少CPU的占用和上下文切换的开销。
LockSupport 是如何工作的?答案:
LockSupport 中的 park 和 unpark 方法是通过底层的 Unsafe 类来实现的,这是一个提供低级别、非安全、操作系统级别访问的类。这些方法直接与JVM的线程调度器交互,将线程置于一种特殊的等待状态,在这种状态下线程不会消耗CPU资源,直到它被 unpark 或中断。
LockSupport 时需要注意什么?答案:
使用 LockSupport 时需要注意以下几点:
park 方法可能会导致线程进入无限期等待,因此需要确保有相应的机制(如中断或 unpark)来唤醒线程。LockSupport 本身不提供锁或其他同步机制,它通常与其他同步原语(如 ReentrantLock)一起使用。LockSupport 是基于底层的 Unsafe 类实现的,因此在使用时需要谨慎,避免在不适当的上下文中使用它。InterruptedException 非常重要,尤其是在使用 LockSupport 时。即使 park 方法本身不会抛出 InterruptedException,但在使用它构建的同步工具中可能需要处理中断。LockSupport 提供了 park 和 unpark 方法,用于阻塞和解除阻塞线程,是构建锁和其他同步工具的基础。与传统的 Thread.sleep() 或Thread.yield() 不同,LockSupport 不需要线程处理 InterruptedException,而且它不会保持任何锁,因此在构建高效、响应式的并发系统时特别有用。
LockSupport.park() 方法允许线程等待某个条件成立,而不会消耗CPU资源,直到它被其他线程 unpark 或被中断。这种等待方式比轮询或使用 sleep() 方法更高效,因为它减少了CPU的占用和上下文切换的开销。
但lockSupport 本身不提供锁或其他同步机制,它通常与其他同步原语(如 ReentrantLock)一起使用,以实现更复杂的同步需求。此外,在使用 LockSupport 时,需要确保有相应的机制来唤醒等待的线程,避免线程进入无限期等待。