- 定义:LockSurport是用来创建锁和其他同步类的基本线程阻塞原语
LockSurport类使用了一种名为permit(许可)的概念来做阻塞和唤醒线程的功能,每个线程都有一个许可(permit)。permit只有0和1两个值,默认是0.
可以把两个值0和1看成信号量(semaphore),但与semaphore不同的是,许可的累加上限是1.
三种让线程等待和唤醒的方法:
- 1、使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程。
- 2、使用JUC包中Condition的await()方法让线程等待,使用signal()方法唤醒线程。
- 3、LockSurport类可以阻塞当前线程(park())以及唤醒指定被阻塞的线程(unpark())
使用wait和notify:
public class TestWaitAndNotify {
static Object objectLock = new Object();
public static void main(String[] args) {
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3); //暂停3秒为了让notify先执行,会导致wait的线程不能被唤醒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
synchronized (objectLock) {
System.out.println(Thread.currentThread().getName()+"---come in");
try {
objectLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---被唤醒");
}
},"A").start();
new Thread(()->{
synchronized (objectLock) {
objectLock.notify();;
System.out.println(Thread.currentThread().getName()+"---通知");
}
},"B").start();
}
}
*************结果***************
B---通知
A---come in
**********************分析:******************
1、wait(),notify(),notifyAll() 必须结合synchronized使用
2、先wait,后notify,否则wait的线程无法被唤醒。
使用await和signal
public class TestAwaitAndSignal {
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void main(String[] args) {
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"---come in");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---被唤醒");
} finally {
lock.unlock();
}
},"A").start();
new Thread(()->{
lock.lock();
try {
condition.signal();
System.out.println(Thread.currentThread().getName()+"----通知");
} finally {
lock.unlock();
}
},"B").start();
}
}
*************结果***************
B---通知
A---come in
**********************分析:******************
1、await(),signal(),signalAll() 必须结合lock使用
2、先await,后signal,否则等待的线程无法被唤醒。
可以发现:synchronized和lock的等待唤醒必须先等待后唤醒,程序才能正常执行。
LockSurport
通过park()和unpark()实现阻塞和唤醒线程的操作。
public class TestLockSurport {
public static void main(String[] args) {
Thread a = new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---come in");
LockSupport.park();//被阻塞,等待通发放许可证permit
System.out.println(Thread.currentThread().getName()+"---被唤醒");
},"A");
a.start();
Thread b = new Thread(()->{
LockSupport.unpark(a);
System.out.println(Thread.currentThread().getName()+"---通知");
},"B");
b.start();
}
}
******************结果:*******************
B---通知
A---come in
A---被唤醒
**********************分析:******************
1、可以看到先通知后等待,也会唤醒等待的线程。
图片.png
当调用park方法时
- 如果有凭证,则会直接消耗掉这个凭证然后正常退出;
- 如果无凭证,就必须阻塞等待凭证可用。
unpark则相反
它会增加一个凭证,但凭证最多只能有1个,累加无效。
网友评论