线程等待和唤醒有三种实现方法,分别是Object类中的wait、notify;Condition类中的await、signal;LockSupport类中的park、unpark方法。
1、Object类中的wait、notify必须配合Synchronized关键字一起使用,否则会抛出IllegalMonitorStateException异常,并且notify唤醒需要在wait之后,否则无法唤醒。
- public static void main(String[] args) {
-
- Object o = new Object();
- new Thread(()->{
- synchronized (o) {
- try {
- o.wait();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- System.out.println("被唤醒");
- }
- }).start();
-
- System.out.println("准备唤醒");
- synchronized (o) {
- o.notify();
- }
- }
2、Condition类中的await、signal必须配合Lock.lock、unlock一起使用,否则会抛出IllegalMonitorStateException异常,并且signal唤醒需要在await之后使用,否则无法唤醒。
- public static void main(String[] args) {
-
- Lock reentrantLock = new ReentrantLock();
- Condition condition = reentrantLock.newCondition();
-
- new Thread(()->{
- reentrantLock.lock();
- try {
- condition.await();
- System.out.println("被唤醒");
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } finally {
- reentrantLock.unlock();
- }
- }).start();
-
- System.out.println("准备唤醒");
-
- reentrantLock.lock();
- try {
- condition.signal();
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } finally {
- reentrantLock.unlock();
- }
- }
3、LockSupport类中的park、unpark属于静态方法,unpark会生成许可证,park会消费许可证。先调用park如果未生成许可证,那么会阻塞等待unpark生成许可证,并不会抛出异常。他们只和线程关联,且线程最多只能有一个许可证,这意味着每次生成凭证之后,需要等消费完才能继续生成凭证。
- public static void main(String[] args) {
- Thread thread = new Thread(() -> {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- LockSupport.park();
- System.out.println("被唤醒");
- });
- thread.start();
-
-
- System.out.println("准备唤醒");
- //断点可以看到unpark先执行,之后执行park
- LockSupport.unpark(thread);
- //thread.start()在unpark之后无效,线程必须启动才能unpark成功
- }