在资源的同步与互斥问题中,最经典的就是“生产者-消费者”问题。生产者-消费者问题的具体含义:系统中有很多生产者和消费者并发的工作,生产者负责生产资源,消费者负责消费资源,当消费者消费资源时,如果资源不足则需要等待;反之当生产者圣餐资源时,如果资源充足,则也需要等待。并且同一时刻只能一个生产者或消费者进行操作。
下面给出具体的代码:
package test11;
public class BreadContainer {
//资源容器最大容量
public static final int MAXNUM = 300;
//资源当前资源的数量
private int num;
public BreadContainer(){};
public synchronized void produceBread(int produceNum, String producerName) {
while(produceNum + num > MAXNUM){
System.out.println("资源充足,不需要生产!"+producerName+" 去等待。。。");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//刷新当前资源数量
num = num +produceNum;
System.out.println(producerName+"生产了"+produceNum+"数量的资源"+",现在共有"+num+"数量的资源!");
//唤醒资源等待池中的所有线程
notifyAll();
}
public synchronized void consumeBread(int consumeNum, String consumerName) {
while(consumeNum > num){
System.out.println("资源不足,不能消费!"+consumerName +"去等待。。。");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//刷新当前资源数量
num = num -consumeNum;
System.out.println(consumerName+"消费了"+consumeNum +"数量的资源"+",现在共有"+num+"数量的资源!");
//唤醒资源等待池中的所有线程
notifyAll();
}
}
注意: 用于生产、消费的同步方法要写在资源中,而不是生产者或消费者的线程中,因为要锁定的是资源对象。需要锁定哪个对象,同步方法就位于哪个对象中。
package test11;
public class Producer extends Thread{
//生产者需要访问的面包容器资源
private BreadContainer bc;
//生产者一次需要生产的面包数量
private int produceNum;
public Producer(){}
public Producer(String name,int produceNum,BreadContainer bc){
this.produceNum = produceNum;
this.bc = bc;
this.setName(name);
}
@Override
public void run() {
//调用资源容器的同步方法生产资源
bc.produceBread(produceNum,this.getName());
}
}
package test11;
public class Consumer extends Thread{
private int consumeNum;
private BreadContainer bc;
public Consumer(){}
public Consumer(String name,int consumeNum,BreadContainer bc){
this.consumeNum = consumeNum;
this.bc = bc;
this.setName( name);
}
@Override
public void run() {
//调用资源容器的同步方法消费资源
bc.consumeBread(consumeNum,this.getName());
}
}
package test11;
public class Main {
public static void main(String[] args) {
BreadContainer bc = new BreadContainer();
Thread p1 = new Producer("p1", 50, bc);
Thread p2 = new Producer("p2", 150, bc);
Thread p3 = new Producer("p3", 100, bc);
Thread c1 = new Consumer("c1", 100, bc);
Thread c2 = new Consumer("c2", 150, bc);
p1.start();
p2.start();
p3.start();
c1.start();
c2.start();
}
}
运行结果:
p1生产了50数量的资源,现在共有50数量的资源!
资源不足,不能消费!c2去等待。。。
资源不足,不能消费!c1去等待。。。
p3生产了100数量的资源,现在共有150数量的资源!
p2生产了150数量的资源,现在共有300数量的资源!
c1消费了100数量的资源,现在共有200数量的资源!
c2消费了150数量的资源,现在共有50数量的资源!
注意:在同步方法中调用的时资源对象的wait方法,让执行同步方法线程去资源的资源等待池中等待。同时,调用的notifyAll方法也是资源对象的,功能时通知资源等待池中的线程出来恢复工作。wait()方法释放锁,而notifyAll()不释放锁,只是起到通知作用,因此即使执行了notifyAll()该语句,锁也不会释放,只有等到任务执行完,锁才会释放。在资源等待池中的线程是没有顺序的,notify()方法只是从资源等待池中任意的选择一个线程唤醒,并不指定恢复哪一个。当多线程访问同一资源时,建议使用notifyAll()唤醒所有线程。
未完待续。。。