1.wait()、notify()、notifyAll()都是Object内的final方法,不可重写。
2.当线程执行wait()方法时,会停止执行,释放当前锁,让出cpu。
3.线程执行notify()方法时会唤醒一个等待中的线程,但不会立即释放锁。notify()唤醒线程后,被唤醒线程会接着上次的执行位置继续往下执行。
4.两个方法都要求在同步代码块中执行,也就是说当前线程已获得锁。
wait()、notify()简单应用场景:
public class T {
//状态锁
private Object lock;
//条件变量
private int now,need;
public void produce(int num){
//获得lock对象锁执行同步代码
synchronized (lock){
//当前有的不满足需要,进行等待
while(now < need){
try {
//调用wait()方法释放对象锁,让出cpu
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我被唤醒了!");
}
//做其他的事情
//调用notifyAll()唤醒所监听lock对象锁的线程
lock.notifyAll();
//同步代码块执行完后释放同步锁
}
}
}
为了更形象的理解等待与唤醒,现假设存在一仓库,仓库中有生产者、消费者、库存。生产者负责将物品生产出并存放至仓库,增加库存;消费者负责将物品移出仓库并消费掉。仓库存在库存上限,如果某次生产后使得物品数量大于库存上限,将不执行本次生产动作,等待消费。如果某次消费后物品数量小于零,将不执行本次消费动作,等待生产。
下面将使用wait()、notify()模拟工厂中物品的生产与消费:
抽象仓库AbstactStorage:
public interface AbstactStorage {
//生产方法
public abstract void produce(int num);
//消费方法
public abstract void consume(int num);
}
仓库类Storage:
import java.util.LinkedList;
public class Storage implements AbstactStorage{
//库存上限
private final int MAX_SIZE = 100;
//库存
private LinkedList<Object> list = new LinkedList<>();
@Override
public void produce(int num) {
synchronized(list) {
while(list.size()+num > MAX_SIZE) {
//仓库满,等待消费
try {
System.out.println("库存:"+list.size()+",生产:"
+num+",无法生产,等待消费");
//释放list对象锁,让出cpu
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print("库存:"+list.size()+",");
for(int i=0;i<num;i++) {
list.add(new Object());
}
System.out.println("生产:"+num+",生产完毕");
//唤醒监听list对象锁的线程
list.notifyAll();
}
}
@Override
public void consume(int num) {
synchronized(list) {
while(num > list.size()) {
try {
System.out.println("库存:"+list.size()+",消费:"
+num+",无法消费,等待生产");
list.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.print("库存:"+list.size()+",");
for(int i=0;i<num;i++) {
list.remove();
}
System.out.println("消费:"+num+",消费完毕");
list.notifyAll();
}
}
}
生产者Producer:
public class Producer extends Thread{
private int num;
private AbstactStorage storage;
public Producer(AbstactStorage storage) {
this.storage = storage;
}
public void setNum(int num) {
this.num = num;
}
public void produce() {
storage.produce(num);
}
@Override
public void run() {
//为了方便观察,不循环执行
produce();
}
}
消费者Consumer:
public class Consumer extends Thread{
private int num;
private AbstactStorage aStorage;
public Consumer(AbstactStorage aStorage) {
this.aStorage = aStorage;
}
public void setNum(int num) {
this.num = num;
}
public void consume() {
aStorage.consume(num);
}
@Override
public void run() {
consume();
}
}
测试:
public class Demo {
public static void main(String[] args) {
//实例化仓库
AbstactStorage storage = new Storage();
//实例化消费者
Consumer c1 = new Consumer(storage);
Consumer c2 = new Consumer(storage);
Consumer c3 = new Consumer(storage);
Consumer c4 = new Consumer(storage);
//实例化生产者
Producer p1 = new Producer(storage);
Producer p2 = new Producer(storage);
Producer p3 = new Producer(storage);
Producer p4 = new Producer(storage);
Producer p5 = new Producer(storage);
Producer p6 = new Producer(storage);
Producer p7 = new Producer(storage);
//设置消费数量
c1.setNum(40);
c2.setNum(40);
c3.setNum(40);
c4.setNum(40);
//设置生产数量
p1.setNum(70);
p2.setNum(60);
p3.setNum(50);
p4.setNum(40);
p5.setNum(30);
p6.setNum(20);
p7.setNum(10);
//启动线程
c1.start();
c2.start();
c3.start();
c4.start();
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
p6.start();
p7.start();
}
}
输出:
参考: