在之前接触过PV操作的,应该对于生产者和消费者的情况有一个了解,这里学到多线程同步的时候,最恰当的一个例子。PV操作就不多做解释。
/**
* 生产者和消费者
* @author bobo
*
*/
public class ProducerConsumer {
public static void main(String[] args) {
SyncStack ss=new SyncStack();
Producer p=new Producer(ss);
Consumer c=new Consumer(ss);
new Thread(p).start();
new Thread(p).start();
new Thread(c).start();
new Thread(c).start();
}
}
//产品-窝头
class WoTou{
int id;
public WoTou(int id){
this.id=id;
}
public String toString(){
return "WOTou : "+id;
}
}
//同步栈,产品盛放的容器
class SyncStack{
int index=0;
WoTou[] arrWT=new WoTou[6];
//向容器中放产品时,其他线程不能使用,已经被锁定
public synchronized void push(WoTou wt){
while(index==arrWT.length){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();//通知消费者,可使用产品
arrWT[index]=wt;
index++;//放入产品
}
//向容器中拿产品时,其他线程不能使用,已经被锁定
public synchronized WoTou pop(){
while(index==0){
try {
this.wait();//如果可拿资源为0,线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();//通知生产者,可以进行生产
index--;
return arrWT[index];//栈中有空位
}
}
//生产者,向容器中放产品
class Producer implements Runnable{
SyncStack ss=null;
Producer(SyncStack ss){
this.ss=ss;
}
public void run(){
for(int i=0;i<20;i++){
WoTou wt= new WoTou(i);
ss.push(wt);
System.out.println("生产者生成:"+wt);
try {
Thread.sleep((int)(Math.random()*200));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//消费者,从容器中取产品
class Consumer implements Runnable{
SyncStack ss=null;
Consumer(SyncStack ss){
this.ss=ss;
}
public void run(){
for(int i=0;i<20;i++){
WoTou wt=ss.pop();
System.out.println("消费者消费:"+wt);
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
有一个容器可以装产品,两边是生产者和消费者,可以是一个也可以是多个。他们为了保证生产者放一个,消费者拿一个,同时也不会出现,生产者还没有放,消费者就可以去拿了,那会使容器中的产品出现负数,这样显然是不对的。
使用synchronized锁定代码块,让生产者向容器放东西的时候,消费者还不能拿到这个产品。
补充:
notify()/notifyAll()
通知,在生产者和消费者这个问题上,当生产者产生产品以后,可以通过信号量,通知消费者,它已经获得了资源。可以进行消费了。
防止大家都在等待,而造成线程阻塞。
wait()和sleep()区别
wait()是Object类中的方法,之后其他人可以使用
sleep()是Thread类的方法,之后其他人也不可以使用