线程同步的一个例子-类似于生产者消费者问题

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;
	}
}
 

你可能感兴趣的:(jvm,多线程,thread)