LockSupport 许可证机制
大约 2 分钟
许可机制
LockSupport使用的许可可看成是一种二元信号,该信号分有许可和无许可两种状态。每个线程都对应一个信号变量,当线程调用park时其实就是去获取许可,如果能成功获取到许可则能够往下执行,否则则阻塞直到成功获取许可为止。而当线程调用unpark时则是释放许可,供线程去获取。
核心函数
LockSupport的核心函数都是基于Unsafe类中定义的park和unpark函数
public native void unpark(Object var1);
public native void park(boolean var1, long var2);
LockSupport类的几个核心方法,总体可以分为以park开头的方法和unpark方法。park开头的方法用于执行阻塞操作,它又分为两类:参数包含阻塞对象和参数不包含阻塞对象。下面对每个方法进行说明。
- park()方法,对当前线程执行阻塞操作,直到获取到可用许可后才解除阻塞,也就相当于当前线程进入阻塞状态。
- parkNanos(long)方法,对当前线程执行阻塞操作,等待获取到可用许可后才解除阻塞,最大的等待时间由传入的参数来指定,一旦超过最大时间它也会解除阻塞。
- parkUntil(long)方法,,对当前线程执行阻塞操作,等待获取到可用许可后才解除阻塞,最大的等待时间为参数所指定的最后期限时间。
- park(Object)方法,与park()方法同义,但它多传入的参数为阻塞对象。
- parkNanos(Object,long)方法,与parkNanos(long)同义,但指定了阻塞对象。
- parkUntil(Object,long)方法,与parkUntil(long)同义,但指定了阻塞对象。
- unpark(Thread)方法,将指定线程的许可置为可用,也就相当于唤醒了该线程。
示例
Thread t1 = new Thread(() -> {
System.out.println("come in t1");
// 获取许可证
// 如果当前线程没有许可,则阻塞在这里,直到另外的线程给当前线程释放许可
LockSupport.park();
System.out.println("out t1");
},"thread1");
t1.start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2 come in");
// 给t1线程释放许可
LockSupport.unpark(t1);
System.out.println("t2 out");
},"thread2").start();
注意事项
每个线程最多只能持有一个许可,下面这段代码将会一致阻塞。
Thread t1 = new Thread(() -> {
System.out.println("第一次阻塞");
LockSupport.park();// 用掉一个许可
System.out.println("第二次阻塞");
LockSupport.park(); // 此时线程没有许可,将阻塞在这里。
System.out.println("out t1");
},"thread1");
LockSupport.unpark(t1);
LockSupport.unpark(t1); // 此时t1线程还是只有一个许可
t1.start();