多个线程并发执行时,CPU是随即切换线程的,为了满足一定要求,就需要使用线程通信.
1.wait方法
作用:使当前线程停止运行,处于等待(阻塞)状态,并释放其持有的对象锁,
wait方法是Object类的方法,调用wait方法,使线程停止在wait()代码行,直到接到通知或被中断为止.
2.notify和notifyAll
其他线程调用此对象的 notify 或 notifyAll ,则唤醒当前对象上等待的线程继续运行,即 重新竞争对象锁.
notify:随即通知一个等待的线程,
notifAll:通知所有等待的线程.
在调用notify或notifyAll方法后,当前线程不会马上释放对象锁,要等到当前线程将程序执行完,即 退出同步方法或同步代码块.
注意:这三个方法必须在同步代码中执行,并且要有同步对象锁,否则会抛出异常!!!
3.wait和sleep对比
- wait 之前需要请求锁,而wait执行时会先释放锁,等被唤醒时再重新请求锁。这个锁是 wait 对像上的 monitorlock
- sleep 是无视锁的存在的,即之前请求的锁不会释放,没有锁也不会请求。
- wait 是 Object 的方法
- sleep 是 Thread 的静态方法
例子:
多生产者和多消费者问题
for (int i = 0; i < 5; i++) {//5个生产者同时工作;
new Thread(() -> {
while (true) {
try {
synchronized (SignalTest.class) {
while (num + 3 > 100) {//库存已满;
SignalTest.class.wait();//等待;
}
num+=3;
System.out.println(Thread.currentThread().getName()+":"+num );
SignalTest.class.notifyAll();//唤醒生产者;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "生产者" + i + "号").start();
``
for(int i=0;i<20;i++){//20个消费者;
new Thread(()->{
try {
while (true){
synchronized(SignalTest.class){
while (num-1<0){//库存不足;
SignalTest.class.wait();//d等待;
}
num-=1;
System.out.println(Thread.currentThread().getName()+" 剩余"+num);
SignalTest.class.notifyAll();//唤醒;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"消费者"+i+"号").start();
}