1 场景
这里介绍一个jdk自带的线程阻塞、唤醒工具LockSupport
。
此工具类属于juc包的一部分,所在包路径:java.util.concurrent.locks.LockSupport。
2 思维导图
已将LockSupport相关的内容整理为思维导图如下:
java阻塞唤醒线程之LockSupport.png3 常用方法
LockSupport的使用方法,均为static方法
。
常用方法如下:
方法 | 描述 |
---|---|
LockSupport.park() | 持续阻塞当前线程 |
LockSupport.park(blocker) | 持续阻塞当前线程 |
LockSupport.parkNanos(nanos) | 超时时间nanos内,阻塞当前线程 |
LockSupport.parkNanos(blocker,nanos) nanos为纳秒 |
超时时间nanos内,阻塞当前线程 |
LockSupport.parkUntil(deadline) | 截止时间deadline内,阻塞当前线程 |
LockSupport.parkUntil(blocker,deadline) deadline为毫秒 |
截止时间deadline内,阻塞当前线程 |
4 优点
使用LockSupport,好处是不会出现死锁
,可以先unpark后park,无论unpark多少此,park一次,即可消费掉。
坏处是,和常见的线程类方法不一样的是,当线程被中断后,不会抛出异常InterruptedException,同时有可能有不可预料的异常,导致阻塞结束。
The call spuriously (that is, for no reason) returns.
5 代码建议
如手动park阻塞后,如需手动unpark唤醒。可参考如下代码:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
public class LockSupportContext {
private AtomicBoolean lockFlag = new AtomicBoolean(false);
private Thread lockThread = new Thread();
public boolean lock() {
lockThread = Thread.currentThread();
lockFlag.set(true);
LockSupport.park(this);
while (!lockFlag.compareAndSet(false, true)) {
// 无限加锁(如考虑非可控的中断,可更改为if,只加一次锁)
LockSupport.park(this);
if (lockThread.isInterrupted()) {
// 解锁失败
return false;
}
}
// 解锁成功
return true;
}
public void unlock() {
lockFlag.set(false);
LockSupport.unpark(lockThread);
}
public static void main(String[] args) throws Exception {
LockSupportContext lockSupportContext = new LockSupportContext();
Thread thread = new Thread(() -> {
System.out.println("子线程-加锁开始");
boolean lockFlag = lockSupportContext.lock();
System.out.println("子线程-加锁结束,解锁结果:" + lockFlag);
});
thread.start();
Thread.sleep(TimeUnit.SECONDS.toMillis(2));
System.out.println("主线程解锁");
lockSupportContext.unlock();
}
}
网友评论