問題引入:模擬一家公司生產電腦與銷售電腦.
設計類:電腦產品類、庫存類、生產者類、消費者類.
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();
}
}
運行結果: 生產先於消費,最後輸出的總是消費的產品.