问题引入:模拟一家公司生产电脑与销售电脑.
设计类:电脑产品类、库存类、生产者类、消费者类.
1、电脑产品类
/** 产品类电脑 **/
class Computer {
int computerid;//产品id
Computer(int computerid) {
this.computerid = computerid;
}
//重写toString方法,便于打印
public String toString() {
return "computer :" + computerid;
}
}
2、库存类
库存里有一个容器,专门是用于存放电脑。从面向对象的角度思考,存放电脑的方法与取出电脑的方法应该分配给库存类本身,而不应该是人(生产者类或消费者类).这两个方法都操作了同一个成员变量,因此要把这两个方法都设置成为同步synchronized。
class Storage {
// 先进先出
LinkedList<Computer> computers = new LinkedList<Computer>();
/** 往库存里放电脑 **/
public synchronized void push(Computer computer) {
while (computers.size()== 20) {// 多次检查要调用while而不能是if
try {
this.wait(); // 不会拿着锁不放,sleep方法就会抱着锁不放
} catch (InterruptedException e) {
e.printStackTrace();
}
}
computers.addLast(computer);
this.notifyAll();
}
/** 从库存里取电脑 **/
public synchronized Computer pop() {
while (computers.size() == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Computer computer =computers.removeFirst();
this.notifyAll();// 唤醒线程
return computer;
}
}
3、生产者类
生产者类应该有一人指向某个库存的引用,将生产的电脑放入指定的库存里.同时也要实现Runnable接口,实现run()方法.
class Producer implements Runnable {
Storage storage = null;
Producer(Storage storage) {
this.storage = storage;
}
public void run() {
for (int i = 0; i < 20; i++) {
Computer computer = new Computer(i);
storage.push(computer);
System.out.println("生产了电脑:" + computer);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4、消费者类
消费者类也应该有一人指向某个库存的引用,指定从哪一个库存里取电脑.同时也要实现Runnable接口,实现run()方法.
class Consumer implements Runnable {
Storage storage = null;
Consumer(Storage storage) {
this.storage = storage;
}
public void run() {
for (int i = 0; i < 20; i++) {
Computer computer = storage.pop();
System.out.println("售出了电脑:" + computer);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
5、测试类
实例化一个库存类对象,让生产者和消费者都同时引用这一个库存对象,然后启动两个线程,一个是生产者,另一个是消费者.
public class ProducerTest2 {
public static void main(String[] args) {
Storage storage = new Storage();
Producer p = new Producer(storage);
Consumer c = new Consumer(storage);
//启动一个生产者的线程
new Thread(p).start();
//启动一个消费者的线程
new Thread(c).start();
}
}
运行结果: 生产先于消费,最后输出的总是消费的产品.