一、生产-消费者模型核心方法
wait()
语义:使得当前线程立刻停止运行,处于等待状态(wait),并将当前线程置入锁对象的等待队列中,直到被通知(notify)或被中断为止
使用条件:只能在同步方法或同步代码块中使用,必须是内建锁。wait方法调用后,立刻释放对象锁
第一版:死等,直到被唤醒或中断
public final void wait() throws InterruptedException {
wait(0);
}
第二版:超时等待,若在规定时间内未被唤醒,则线程退出
public final native void wait(long timeout) throws InterruptedException;
//毫秒级别
public final void wait(long timeout, int nanos) throws InterruptedException {
//毫秒+纳秒
notify()
语义:唤醒处于等待状态的线程
使用条件:在同步方法或同步代码块中调用,用来唤醒等待该对象的其他线程。如果有多个线程等待,随机挑选一个唤醒。
注意:该方法调用后,当前线程不会立刻释放锁,要等到当前线程执行完毕后再释放锁,与wait是同一个对象
notifyAll()
唤醒所有该对象处于等待状态的线程
二、 线程由运行状态–>阻塞(wait)
1.调用sleep(),立刻交出CPU,不释放锁
2.线程调用阻塞式IO(BIO)方法
3.线程获取锁失败进入阻塞状态
4.线程调用wait()
5.线程调用suspend(),将线程挂起
每个锁对象都有两个队列:
同步队列,存储获取锁失败的线程
等待队列,存储调用wait等待的线程
将线程唤醒实际上是将处于等待队列的线程移到同步队列中竞争锁。
三、 生产-消费者模型
1.单生产者,单消费者(一个生产者生产一次商品,一个消费者只消费一次)
import java.util.ArrayList;
import java.util.List;
//商品类
class Goods{
private String goodsName;
private int count;
//生产商品方法
public synchronized void setGoods(String goodsName) throws InterruptedException {
//当前还有商品,等待消费者消费
if(count > 0){
System.out.println("还有商品,稍等");
wait();
}
this.goodsName = goodsName;
this.count++;
System.out.println("生产"+toString());
//生产产品后唤醒消费者
notify();
}
//消费商品方法
public synchronized void getGoods() throws InterruptedException {
//当前还没有商品,消费者需要等待
if(this.count == 0){
System.out.println("商品卖完了,请稍后");
wait();
}
this.count--;
System.out.println("消费"+toString());
//消费完商品后先告诉生产者继续生产
notify();
}
@Override
public String toString() {
return "Goods [goodsName +"+goodsName+",库存为"+count+"]";
}
}
//生产者
class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods){
this.goods = goods;
}
@Override
public void run() {
try {
this.goods.setGoods("小汽车");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//消费者
class Costumer implements Runnable{
private Goods goods;
public Costumer(Goods goods){
this.goods = goods;
}
@Override
public void run() {
try {
this.goods.getGoods();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class singleProducer {
public static void main(String[] args) {
Goods goods = new Goods();
List list = new ArrayList<>();
Producer producer = new Producer(goods);
Costumer costumer = new Costumer(goods);
//5个生产者
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(producer,"生产者");
list.add(thread);
}
//10个消费者
for (int i = 0; i < 10 ; i++) {
Thread thread = new Thread(costumer,"消费者");
list.add(thread);
}
for (Thread thread:list){
thread.start();
}
}
}
2.多生产者,多消费者(生产多个,消费多个)
将上述代码进行修改:
if -----> while():生产完后需要再次检查条件是否满足
notify -----> notifyall:否则只唤醒一个生产者,恰好被消费,会导致互相等待,死锁
四、sleep()与wait()的区别
sleep()是Thread类中定义的方法,到了一定时间后该线程自动唤醒,不会释放对象锁
wait()是Object类中定义的方法,必须使用notify(),notifyAll()方法才能唤醒,会释放对象锁