J.U.C之LockSupport
一、与wait/notify区别
wait/notify 为Object中的方法,在调用这两个方法前必须要先获得对象的锁,而locksupport则无需获取对象锁就可以锁定指定线程。
nodify 只能唤醒任意线程,而locksupport 可以唤醒指定线程,且park不需要捕获中断异常,wait 需要。
二、怎么用
主要是park/unpark, park字面意思停车,形象解释为叫这个线程你站住,你停一下。unpark 就是你继续走。park 和 unpark 就是一个消耗许可和产生许可的过程。底层维护了一个计数器_counter, 多次调用unpark 只会多次将_counter置为1,而不是加1,简单说就是:线程A连续调用两次LockSupport.unpark(B)方法唤醒线程B,然后线程B调用两次LockSupport.park()方法, 线程B依旧会被阻塞。因为两次unpark调用效果跟一次调用一样,只能让线程B的第一次调用park方法不被阻塞,第二次调用依旧会阻塞。每一个线程都会维护着这样一个许可.
public static void park() {
UNSAFE.park(false, 0L);
}
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
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);
示例:
public class LockSupportTest {
public static class MyThread extends Thread{
@Override
public void run() {
System.out.println("线程开始等待..");
LockSupport.park();
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程结束等待..");
}
}
public static void main(String[] args){
Thread _t = new MyThread();
_t.start();
System.out.println("开始唤醒线程..");
LockSupport.unpark(_t);
System.out.println("唤醒线程结束..");
}
}
输出:
开始唤醒线程..
线程开始等待..
唤醒线程结束..
线程结束等待..
public class LockSupportTest {
public static class MyThread extends Thread{
@Override
public void run() {
System.out.println("线程开始等待..");
System.out.println("第1个park开始...");
LockSupport.park();
System.out.println("第1个park结束...");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第2个park开始..");
LockSupport.park();
System.out.println("第2个park结束..");
System.out.println("线程结束等待..");
}
}
public static void main(String[] args){
Thread _t = new MyThread();
_t.start();
System.out.println("开始唤醒线程..");
LockSupport.unpark(_t);
LockSupport.unpark(_t);
System.out.println("唤醒线程结束..");
}
}
输出: 可以看出第2个park未能获取到锁,一直等待
开始唤醒线程..
线程开始等待..
第1个park开始...
唤醒线程结束..
第1个park结束...
第2个park开始..