生产者消费者模式的实现
生产者消费者模式原理:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。
产生的问题:数据错乱,如:生产者生产旺仔-牛奶,和娃哈哈-矿泉水。用一个商品类表示生产者和消费者共享的数据,类中有两属性商品的品牌(brand)和商品的名称(name)。假设生产者生产一种产品,当被消费了再继续生产。当生产者生产产品时,即向商品类中写入数据,如(brand=“旺仔”;name=“牛奶”);然后消费者就行消费,即读取数据(brand=“旺仔”;name=“牛奶”);当生产者再向商品类中写入数据时(娃哈哈-矿泉水),如只赋值了brand="娃哈哈"时,由于线程并发的原因,可能此时生产者赋值被阻塞,然后消费者类就行读取数据,此时读出来的是(brand=“娃哈哈”;name=“牛奶”),所以数据就错乱了。还可能出现重复生产和重复取走。
解决方法:线程间的通信,即当生产执行完之后才进行消费,当消费执行完再进行生产,这样彼此之间不进行干扰。
线程间的通信
线程间通信的方法(以下是Object类中的方法)
wait():调用了wait()方法的线程进入等待池进行等待,等待池中的线程不去竞争对象锁,直到其他线程唤醒才能有资格获取资源继续执行。
notify():随机唤醒一个在该对象上等待的线程。
notifyAll():唤醒所有在该对象上等待的线程。
Thread.sleep()和Object.wait()的区别
Thread.sleep()和Object.wait()都会暂停当前的线程,这两张方式暂停的线程,都表示它暂时不再需要CPU的执行时间。操作系统会将执行时间分配给其它线程。区别是调用wait()后,需要别的线程执行notify()/notifyAll()才能够重新获得CPU执行时间。
生产者消费者模式的代码实现
商品类:
public class Goods {
private String brand;
private String name;
public boolean flag;//判断是否有商品
public Goods(String brand, String name) {
this.brand = brand;
this.name = name;
}
public Goods(){}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 设置brand和name
public synchronized void set(String brand,String name){
if(flag){
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setBrand(brand);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
setName(name);
System.out.println("生产者生产了:"+brand+"-"+name);
flag = true;
super.notify();
}
// 获取值
public synchronized void get(){
if(!flag){
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费者获取了:"+brand+"-"+name);
flag=false;
super.notify();
}
}
生产者类:
public class Producter extends Thread{
Goods good = new Goods();
public Producter(Goods good){
this.good = good;
}
@Override
public void run() {
for(int i=0;i<10;i++){
if(i%2==0){
good.set("旺仔","牛奶");
}else{
good.set("娃哈哈","矿泉水");
}
}
}
}
消费者类:
public class Customer extends Thread{
Goods good = new Goods();
public Customer(Goods good){
this.good = good;
}
@Override
public void run() {
for (int i=0;i<10;i++){
good.get();
}
}
}
测试类:
public class Test {
public static void main(String[] args) {
Goods goods = new Goods();
Producter pr = new Producter(goods);
Customer ct = new Customer(goods);
pr.start();
ct.start();
}
}
代码解读:生产者对商品类中的属性赋值,当商品类中有产品(即已赋值),标识flag=true;如果flag=true,生产者的赋值代码块调用wait()进行等待,而消费者进行取值(即取出商品了),flag=false,同时调用方法notifyAll()进行唤醒生产者的生产行为(进行赋值)。如果flag=false,生产者的赋值行为可以执行,消费者的取值需要进行等待,要等生产者赋值结束了才被唤醒。