常用方法
public static void park(Object blocker); // 暂停当前线程
public static void parkNanos(Object blocker, long nanos); // 暂停当前线程,不过有超时时间的限制
public static void parkUntil(Object blocker, long deadline); // 暂停当前线程,直到某个时间
public static void park(); // 无期限暂停当前线程
public static void parkNanos(long nanos); // 暂停当前线程,不过有超时时间的限制
public static void parkUntil(long deadline); // 暂停当前线程,直到某个时间
public static void unpark(Thread thread); // 恢复当前线程
public static Object getBlocker(Thread t);
unpark(Thread thread)是给资源一个许可,可以继续执行,而这个许可时一对一的,一个unpark只能抵消一个park。但是unpark和park前后顺序无所谓。park()/unpark()底层的原理是“二元信号量”,你可以把它相像成只有一个许可证的Semaphore,只不过这个信号量在重复执行unpark()的时候也不会再增加许可证,最多只有一个许可证。
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread1 start");
try{
Thread.sleep(2000);
} catch (Exception e){
e.printStackTrace();
}
System.out.println("thread1 run before park");
LockSupport.park();
System.out.println("thread1 run after park");
}
});
thread1.start();
LockSupport.unpark(thread1);
上例执行结果
再增加一个park
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread1 start");
try{
Thread.sleep(2000);
} catch (Exception e){
e.printStackTrace();
}
System.out.println("thread1 run before park");
LockSupport.park();
LockSupport.park();
System.out.println("thread1 run after park");
}
});
thread1.start();
LockSupport.unpark(thread1);
卡住
blocker
作为阻塞线程的标志
public static void park(Object blocker) {
// 获取当前线程
Thread t = Thread.currentThread();
// 设置Blocker
setBlocker(t, blocker);
// 获取许可
UNSAFE.park(false, 0L);
// 重新可运行后再此设置Blocker
setBlocker(t, null);
}
LockSupport.park("myblocker");
LockSupport.getBlocker(Thread.currentThread());//返回myblocker
Thread.interrupt()
调用此函数可以唤醒一个park的线程
Object.wait()/notify()
park/unpark相比较于Object.wait()和Object.notify()只能先wait后notify而言更灵活
static class MyThread extends Thread {
public void run() {
synchronized (this) {
System.out.println("before notify");
notify();//唤醒wait阻塞线程
System.out.println("after notify");
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
synchronized (myThread) {
try {
myThread.start();
// 主线程睡眠3s
Thread.sleep(3000);
System.out.println("before wait");
// 阻塞主线程,并释放synchronized中的锁
//一定要使用当前的锁进行wait,这样等于释放锁了。
//尝试使用Thread.currentThread().wait()报错current thread is not owner
myThread.wait();
//有notify唤醒并获得锁才能继续执行
System.out.println("after wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果
Object.wait()方法需要在synchronized块中执行;
LockSupport.park()可以在任意地方执行;
Object.wait()方法声明抛出了中断异常,调用者需要捕获或者再抛出;
LockSupport.park()不需要捕获中断异常;
Object.wait()不带超时的,需要另一个线程执行notify()来唤醒,但不一定继续执行后续内容; LockSupport.park()不带超时的,需要另一个线程执行unpark()来唤醒,一定会继续执行后续内容;
参考
https://pdai.tech/md/java/thread/java-thread-x-lock-LockSupport.html#%E4%BD%BF%E7%94%A8waitnotify%E5%AE%9E%E7%8E%B0%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%AD%A5