生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者从空间里取走数据。
解决方式:要考虑线程安全的问题,解决此问题有三种方式
同步代码块
同步方法
lock锁机制, 经过建立Lock对象,采用lock()加锁,unlock()解锁,来保护指定的代码块复制代码
此文采用第二种方式解决了线程安全问题 java
wait()、nofity()这两个方法必须有锁对象调用,而任意对象均可以做为 synchronized 的同步锁,所以这三个方法只能在Object 类中声明 。
wait():当缓冲区已满/空时,生产者或消费者线程中止本身的执行,释放锁,使本身处于等待状态,让其它线程执行。 安全
notify():当生产者或消费者向缓冲区放入或取出一个产品时,向其余等待的线程发出通知,同时释放锁,使本身处于等待状态,让其它线程执行。 bash
商店类(Shop):定义一个成员变量,表示第几个面包,提供生产面包和消费面包的操做;
生产者类(Producer):实现Runnable接口,重写run()方法,调用生产面包的操做;
消费者类(Consumer):实现Runnable接口,重写run()方法,调用消费面包的操做;
测试类:
/**
* 商店类(Shop):定义一个成员变量,表示第几个面包,提供生产面包和消费面包的操做;
*/
class Shop {
private int bread = 0;
/**
* 生产面包
*/
public synchronized void produceBread() {
if (bread < 10) {
bread++;
System.out.println(Thread.currentThread().getName() + ":开始生产第" + bread + "个面包");
notify(); // 唤醒消费者线程
} else {
try {
wait(); // 告诉生产者等待一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 消费面包
*/
public synchronized void consumeBread() {
if (bread > 0) {
System.out.println(Thread.currentThread().getName() + ":开始消费第" + bread + "个面包");
bread--;
notify(); // 唤醒生产者线程
} else {
try {
wait(); // 告诉消费者等待一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 生产者类(Producer):实现Runnable接口,重写run()方法,调用生产面包的操做
*/
class Producer extends Thread {
private Shop shop;
public Producer(Shop shop) {
this.shop = shop;
}
@Override
public void run() {
System.out.println(getName() + ":开始生产面包.....");
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
shop.produceBread();
}
}
}
/**
* 消费者类(Consumer):实现Runnable接口,重写run()方法,调用消费面包的操做
*/
class Consumer extends Thread {
private Shop shop;
public Consumer(Shop shop) {
this.shop = shop;
}
@Override
public void run() {
System.out.println(getName() + ":开始消费面包.....");
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
shop.consumeBread();
}
}
}
public class BreadTest {
public static void main(String[] args) {
// 建立商店对象
Shop shop = new Shop();
// 建立生产者对象,把商店对象做为构造方法参数传入生产者对象中
Producer p1 = new Producer(shop);
p1.setName("生产者");
// 建立消费者对象,把商店对象做为构造方法参数传入消费者对象中
Consumer c1 = new Consumer(shop);
c1.setName("消费者");
p1.start();
c1.start();
}
}复制代码
代码执行结果以下: ide
消费者:开始消费面包.....
生产者:开始生产面包.....
生产者:开始生产第1个面包
生产者:开始生产第2个面包
生产者:开始生产第3个面包
生产者:开始生产第4个面包
消费者:开始消费第4个面包
生产者:开始生产第4个面包
生产者:开始生产第5个面包
生产者:开始生产第6个面包
生产者:开始生产第7个面包
生产者:开始生产第8个面包
消费者:开始消费第8个面包
生产者:开始生产第8个面包
生产者:开始生产第9个面包
生产者:开始生产第10个面包
消费者:开始消费第10个面包
生产者:开始生产第10个面包
消费者:开始消费第10个面包
生产者:开始生产第10个面包
消费者:开始消费第10个面包
生产者:开始生产第10个面包
消费者:开始消费第10个面包
...
复制代码
欢迎你们有兴趣的能够关注个人公众号【java小瓜哥的分享平台】,文章都会在里面更新,还有各类java的资料都是免费分享的。但愿与你们一块儿进步努力!测试