LockSupport类的park()方法和unpark(Thead t)方法通常用于线程之间的阻塞和唤醒,但是这两个方法比较强大,前后不需要加锁,执行顺序也不限制,他们之间的约束靠的是信号量,下面是例子。
1、正常使用的代码
public class ParkAndUnPark {
public static void main(String[] args) {
Thread t1 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"进来啦,然后被park阻塞");
//消耗一个凭证,若没得消耗则阻塞
LockSupport.park();
System.out.println(Thread.currentThread().getName()+"被唤醒啦");
},"t1");
t1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"unpark唤醒了t1");
//产生一个凭证,最多产生一个,不管unpark多少次
LockSupport.unpark(t1);
},"t2").start();
}
}
输出结果
t1进来啦,然后被park阻塞
t2unpark唤醒了t1
t1被唤醒啦
跟预想的一致。
2、park()和unpark()不需要加锁
它们之间靠的是凭证,park()消耗一个凭证,若没有则阻塞,有则不阻塞。unpark()生成一个凭证,不管调用多少次都只能生成一个,最大是1.
3、如果先执行unpark()后执行park()则不会阻塞
原因是unpark()先放了一个凭证,所以park()的时候,凭证已经存在则不阻塞继续执行。
public class ParkAndUnPark {
public static void main(String[] args) {
Thread t1 = new Thread(()->{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"进来啦,然后被park阻塞");
//消耗一个信号量,若没得消耗则阻塞
LockSupport.park();
System.out.println(Thread.currentThread().getName()+"被唤醒啦");
},"t1");
t1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"unpark唤醒了t1");
//产生一个信号量,最多产生一个,不管unpark多少次
LockSupport.unpark(t1);
},"t2").start();
}
}
t2unpark唤醒了t1
t1进来啦,然后被park阻塞
t1被唤醒啦