import java.util.Stack;
/*
* 多线程同步例子:当厨师线程开始执行put方法或者服务员开始get方法时,都必须先获取MediContainer对象的锁,
* 如果该锁被其他线程占用,另一个线程就只能在锁池中等待。这种锁机制使得厨师线程执行put方法的整个过程中
* ,服务员线程不会执行get方法,同样,在服务员线程在执行get方法的整个过程中,厨师线程不执行put方法。
*
* 注意,一个对象的wait方法和notify方法的调用应该放在同步代码块中,并且同步代码块采用这个对象的锁,
若果违背了这个规则,尽管在编译时不会检查这种错误,但在运行时会跑出IllegalMonitorException异常
*/
public class MutilThreadTest {
public static void main(String args[]){
MediContainer med=new MediContainer(5);
Thread thread[]={
new Cook(med),
new Cook(med),
new Waitress(med),
new Waitress(med),
new Waitress(med)
};
thread[0].setName("cooker1");
thread[1].setName("cooker2");
thread[2].setName("waitress1");
thread[3].setName("waitress2");
thread[4].setName("waitress3");
for(int i=0;i<thread.length;i++){//同时启动两个厨师线程,3个服务员线程
thread[i].start();
}
try {
Thread.sleep(2000);//运行2s后停止运行
med.setStop(true);
System.out.println("over");
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<thread.length;i++){
thread[i].stop();
}
}
}
class MediContainer{//定义食物存储容器
public static Stack<Dish> slot=new Stack<Dish>();
public int slotCount;
public boolean stopflag=false;
public MediContainer(int slotcount){
this.slotCount=slotcount;
}
public void setStop(boolean flag){
this.stopflag=flag;
}
public boolean isStop(){
return this.stopflag;
}
public void put(Dish dish){//厨师放菜操作,当slot容器中炒菜数量为最大值时,该容器对象this.wait(),此时调用该方法的线程进入该对象的锁池
synchronized(this){
this.notifyAll();
//唤醒对象等待池中其余的等待线程,即JVM将该对象等待池中的对象都移到锁池中,在这里等待获得锁
//实际意义是,通知在等待池中的线程(准备从容器中取炒菜的服务员线程)准备到锁池中准备执行
while(slot.size()==this.slotCount){
try {
System.out.println(Thread.currentThread().getName()+"厨师等待放菜....");
this.wait();//此时,容器已满,厨师放弃对象锁和cpu进入该对象的等待池中
} catch (InterruptedException e) {
e.printStackTrace();
}
}
slot.push(dish);
System.out.println(Thread.currentThread().getName()+"完成一个炒菜,此时炒菜数量:"+slot.size());
}
}
public Dish get(){
synchronized(this){
this.notifyAll();
//唤醒对象等待池中其余的等待线程,即JVM将该对象等待池中的对象都移到锁池中,在这里等待获得锁;
//实际意义是,通知在等待池中的线程(准备往容器中放炒菜的厨师线程)准备到锁池中准备执行
while(slot.size()==0){
try{
System.out.println(Thread.currentThread().getName()+"服务员等待端菜....");
this.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"服务员取走一个炒菜,此时还剩炒菜数量:"+(slot.size()-1));
return slot.pop();
}
}
}
class Cook extends Thread{//定义一个厨师线程
private int id;
MediContainer med;
public static int number=1;
public Cook(MediContainer med){
this.id=number++;
this.med=med;
}
public void run(){
while(!med.isStop()){
Dish dish=new Dish(id);
med.put(dish);//该方法是同步方法,此时该对象必须获取med对象的同步锁,如果该锁被其他线程占用,则该对象进入med对象的锁池中阻塞
try {
Thread.sleep(10);//放弃cpu,将运行机会给别的线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Waitress extends Thread{
private int id;
MediContainer med;
public static int number=1;
public Waitress(MediContainer med){
this.id=number++;
this.med=med;
}
public void run(){
while(!med.isStop()){
Dish dish=med.get();//该方法是同步方法,此时该对象必须获取med对象的同步锁,如果该锁被其他线程占用,则该对象进入med对象的锁池中阻塞
try {
Thread.sleep(200);//放弃cpu,将运行机会给别的线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Dish{
public int id;
public Dish(int id){
this.id=id;
}
}
线程同步的一个例子-类似于生产者消费者问题
最新推荐文章于 2021-02-09 05:45:27 发布