本文为视频笔记:P50-P55
链接:尚硅谷并发编程
已知Object类、ReentrantLock.newCondition、LockSupport类都有提供等待唤醒机制:
Object类和ReentrantLock.newCondition提供的阻塞唤醒机制十分相似,体现在:
LockSupport类与前两者不同:
package com.example.juc.LockCondition;
public class TestObj {
public static void main(String[] args) {
TestObj obj = new TestObj(); // 1. 待会借此生成一个sync锁
Thread t1 = new Thread(() -> {
synchronized (obj) { // 2.1 记得锁住同个对象
System.out.println("start。。。。");
try {
obj.wait(10000); // 阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end。。。。");
}
});
t1.setPriority(9);
t1.start();
new Thread(() -> {
synchronized (obj) { // 2.2 记得锁住同个对象
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("唤醒t1.....");
obj.notify(); // 通知唤醒t1
}
}).start();
}
}
先看个翻车日常,使用await和signal时并没有使用同个condition调用,结果被阻塞的线程没有真正被通知唤醒:

此外,以上的try catch写得也不太规范。加锁代码应放在try之外,释放锁应该写在finally内。
正确代码演示:
package com.example.juc.LockCondition;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestCondition {
private static ReentrantLock lock = new ReentrantLock();
private static Condition condition = lock.newCondition(); // await和signal都要使用同一个condition!
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
lock.lock(); // 代码规范1
try {
System.out.println("开始阻塞");
condition.await(10000, TimeUnit.MILLISECONDS); // 阻塞
System.out.println("结束阻塞");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 代码规范2
}
});
t1.setPriority(9);
t1.start();
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(1000); // 此处设置休眠是想让t1先跑一会
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
System.out.println("唤醒t1...");
condition.signal();
lock.unlock();
}).start();
}
}
package com.example.juc.LockCondition;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class TestPark {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println("开始阻塞");
LockSupport.park(10000); // 阻塞
System.out.println("结束阻塞");
});
t1.setPriority(9);
t1.start();
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(1000); // 此处设置休眠是想让t1先跑一会
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("唤醒t1...");
LockSupport.unpark(t1); // 唤醒t1,给t1一个凭证
}).start();
}
}
使用这几种阻塞唤醒机制时,要注意一些细节,不要抛异常就OK
