LockSupport的凭证(通常称为“许可”或“permit”)的底层原理主要涉及到Java的Unsafe类以及系统级的线程同步机制。LockSupport是Java 6(JSR166-JUC)引入的一个类,提供了基本的线程同步原语,其核心功能是通过park()和unpark()方法实现线程的阻塞和唤醒。以下是对LockSupport凭证底层原理的详细解释:
1. 凭证的概念
在LockSupport中,每个线程都与一个“许可”(permit)相关联。这个许可类似于一个开关,其状态只能是0或1。当线程调用park()方法时,它会检查是否有可用的许可:
如果有许可(permit为1),则线程继续执行,同时许可被消耗(permit变为0)。
如果没有许可(permit为0),则线程被阻塞,直到其他线程调用unpark()方法为该线程提供许可。
2. Unsafe类的作用
LockSupport实际上是调用了Unsafe类中的函数来实现其功能。Unsafe类提供了一系列的native方法,允许Java代码执行一些低层次、不安全但强大的操作,比如直接内存访问、线程调度等。对于LockSupport来说,主要涉及到两个native方法:
public native void park(boolean isAbsolute, long time);:阻塞当前线程,直到有许可可用或等待超时。
public native void unpark(Thread jthread);:为给定线程提供许可,使其能够解除阻塞。
3. 底层实现机制
在HotSpot JVM中,LockSupport的park()和unpark()方法通过操作每个Java线程的Parker实例来实现。Parker类是一个用C++编写的类,它封装了系统级的线程同步机制(如POSIX的mutex和condition variable)。Parker类中有一个关键的字段_counter,用来记录许可的数量。
当线程调用park()方法时,它会检查_counter的值:
如果_counter大于0,则线程获取许可并继续执行,同时_counter减1。
如果_counter等于0,则线程被阻塞,直到其他线程调用unpark()方法将_counter设置为1并唤醒该线程。
当线程调用unpark()方法时,它会将目标线程的Parker实例的_counter设置为1(如果之前小于1的话),并可能通过系统级的条件变量唤醒该线程。
4. 灵活性与优势
与Object的wait/notify机制相比,LockSupport的park/unpark模型具有更高的灵活性和更低的复杂性。它不需要线程之间共享任何对象来存储状态,也无需关心对方的状态。此外,unpark()方法可以先于park()方法调用,这意味着线程可以在需要时随时被唤醒,而无需担心调用顺序的问题。
总结
LockSupport的凭证(许可)底层原理主要依赖于Unsafe类中的native方法以及系统级的线程同步机制。通过为每个线程关联一个许可,并使用park()和unpark()方法来实现线程的阻塞和唤醒,LockSupport为Java并发编程提供了强大而灵活的同步原语。