多線程的開發中有一個最經典的操作案例,就是生産者--》消費者, 生産者不斷生産産品, 消費者不斷取走産品。
例如:飯店裡的一個廚師和一個服務員, 這個服務員必須等待廚師準備好膳食。當廚師準備好時,他會通知服務員,之後服務員上菜,然後傳回繼續等待。 這是一個任務協作的執行個體, 廚師代表生産者, 而服務員代表消費者。
火車票售賣: 在春運的時候, 火車可以通過網上購票和人工視窗購票的方式進行買票, 總票數固定, 各大視窗的票數根據這個總票數售賣,同一張票需被一個人購買, 不能同時一個人擁有同一個票,這是會發生打架的。票數要一緻後, 在不同視窗售賣,就需要保證票數同步, 且同一張票隻能由一個對象擁有, 不能同時售賣不同人。
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() {
}
}