多线程的开发中有一个最经典的操作案例,就是生产者--》消费者, 生产者不断生产产品, 消费者不断取走产品。
例如:饭店里的一个厨师和一个服务员, 这个服务员必须等待厨师准备好膳食。当厨师准备好时,他会通知服务员,之后服务员上菜,然后返回继续等待。 这是一个任务协作的实例, 厨师代表生产者, 而服务员代表消费者。
火车票售卖: 在春运的时候, 火车可以通过网上购票和人工窗口购票的方式进行买票, 总票数固定, 各大窗口的票数根据这个总票数售卖,同一张票需被一个人购买, 不能同时一个人拥有同一个票,这是会发生打架的。票数要一致后, 在不同窗口售卖,就需要保证票数同步, 且同一张票只能由一个对象拥有, 不能同时售卖不同人。
package com.vince;
/**
* 两个线程协同工作,先生产,再消费
* 面试题
* sleep 与 wait的区别
* sleep :让线程进入休眠状态,让出cpu的时间片,不释放对象监视器的所有权(对象锁)
* wait 让线程进入等待状态,让出cpu的时间片,并释放对象监视器的所有权,等待其他线程通过notify唤醒线程。
*/
public class ThreadDemo1 {
public static void main(String[] args) {
Food food = new Food();
Producter p = new Producter(food);
Customer c = new Customer(food);
Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
/**
* 生产者
*/
class Producter implements Runnable{
private Food food;
public Producter(Food food){
this.food=food;
}
public void run(){
for (int i = 0; i < 20; i++) {
if(i%2==0){
food.set("锅包肉,酸甜口味","爽");
}else{
food.set("佛跳墙,滋阴补阳","大补");
}
}
}
}
/**
* 消费者
*/
class Customer implements Runnable{
private Food food;
public Customer(Food food){
this.food=food;
}
public void run(){
for (int i = 0; i < 20; i++) {
food.get();
}
}
}
/**
* 食物
*/
class Food{
private String name;
private String desc;
private boolean flag=true; //true表示可以生产,false表示可以消费
/**
* 生产产品
*/
public synchronized void set(String name,String desc){
//不能生产
if(!flag){
try {
this.wait(); //线程进入等待状态,释放监视器的所有权(对象锁)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//设置菜名
this.setName(name);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//设置菜的描述
this.setDesc(desc);
flag=false;
this.notify(); //唤醒等待的线程(随机的其中一个)
}
/**
* 消费产品
*/
public synchronized void get(){
//不能消费
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getName()+"--->"+this.getDesc());
flag=true;
this.notify();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Food{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
public Food(String name, String desc) {
this.name = name;
this.desc = desc;
}
public Food() {
}
}