线程的等待和唤醒的三种方式
1.使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程,使用必须持有锁
public class LockSupportDemo {
public static void main(String[] args) {
Object lockObject = new Object();
Thread t1 = new Thread(() -> {
synchronized (lockObject) {
try {
lockObject.wait();
System.out.println("t1 被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread t2 = new Thread(() -> {
synchronized (lockObject) {
System.out.println("唤醒t1");
lockObject.notify();
}
}, "t2");
t2.start();
}
}
调用wait()和notify()方法时,必须持有锁,否则报
java.lang.IllegalMonitorStateException
将notify放在wait方法前面,程序无法执行,无法唤醒
2. 使用JUC包中Condition的await()方法让线程等待,使用signal()方法唤醒线程,使用必须持有锁
public class LockSupportCondition {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(()->{
lock.lock();
System.out.println(Thread.currentThread().getName() + "come in");
try {
condition.await();
System.out.println(Thread.currentThread().getName() + "\t-------waked");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
lock.lock();
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t-------signal");
lock.unlock();
}, "t2").start();
}
}
调用await()和signal()方法时,必须持有锁,否则报
java.lang.IllegalMonitorStateException
先await() 后signal,不能反了
3.LockSupport类可以park阻塞当前线程以及unpark唤醒指定被阻塞的线程
LockSupport的方法
常用方法
park()
- 如果有凭证,则会直接消耗掉这个凭证然后正常退出
- 没有凭证,就会阻塞等待凭证可用
unpark()
- 增加一个凭证,但凭证最多只能有一个
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语
LockSupport类使用一种名为(Permit)许可的概念做到阻塞和唤醒的功能
,每个线程都有一个许可(permit),许可的累加上限是1
LockSupport类的特点:
- 正常+无锁块要求
- LockSupport支持先唤醒后等待
- 成双成对
public class LockSupportDemoPark {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "-------come in");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "-------waked");
}, "t1");
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread t2 = new Thread(() -> {
// System.out.println(Thread.currentThread().getName() + "-------come in");
LockSupport.unpark(t1);
System.out.println(Thread.currentThread().getName() + "-------唤醒t1");
}, "t2");
t2.start();
}
}
park unpark 无顺序要求。因为park发了许可证,线程没使用,会保留,许可证不会积累,最多只有一个