下面举一个两个线程共享同一个数据的例子。
先用一幅图来说明这个消费者生产者关系
ProductList
是一个生产者跟消费者共享的同步机制,这个机制决定了什么情况生产者要wait(),
什么情况消费者要wait()。可以把ProductList看做一个产品仓库.当产品仓库满的时候,生产者线程需要wait(),从而放弃对产品仓库的控制。这个时候消费者线程就可以进来了且取得仓库的控制权。一旦消费者消费了产品,那么仓库就不满了,这个时候消费者线程就要notifyAll()生产者线程让等待的生产者线程唤醒。但是生产者被唤醒后不能马上进行生产,因为它在wait()的时候已经丧失了对仓库的控制权,所以就需要等待消费者线程结束操作,才能重新取得仓库的控制权,再进行生产。
所以特别注意的是,notifyAll()并不是让当前线程马上让出控制权,而只是让其他wait()当中的
线程唤醒而已,所以尽管我唤醒你,可你必须还是要等我用完仓库才能进来。相反,仓库如果空的时候,消费者线程就会wait(),然后等待生产者线程来生产产品,生产者进程乘虚而入后,让生产者线程生产产品并且唤醒消费者线程,这个情况跟上面就类似了。
(1)、产品类
public class Product {
int id;
private String producedBy="N/A";
private String consumedBy="N/A";
//构造函数,指明生产者名字
public Product(String ProducedBy){
this.producedBy=ProducedBy;
}
//消费,需要指明消费者名字
public void consume(String ConsumedBy){
this.consumedBy=ConsumedBy;
}
public String getProducedBy() {
return producedBy;
}
public void setProducedBy(String producedBy) {
this.producedBy = producedBy;
}
public String getConsumedBy() {
return consumedBy;
}
public void setConsumedBy(String consumedBy) {
this.consumedBy = consumedBy;
}
@Override
public String toString() {
return "产品,生产者=" + producedBy + '\'' +
", 消费者='" + consumedBy + '\'' +
'}';
}
}
(2)、产品产库类
产品仓库类包含了一个大小为6的数组,表示最大的产品容量,它包含两个同步的方法。
push():生产者调用该方法加入一个新的产品。如果仓库满了,那么就使用wait()等待,直到被消费者通知后再继续添加该商品到仓库中。一旦添加了商品,就需要调用notifyAll()通知其他的消费者来消费。
pop():消费者调用该方法消费一个产品。如果仓库中没有商品,那么就使用wait()等待,直到被生产者通知后再继续消费。一旦消费了商品,就需要调用notifyAll()通知其他的生产者继续生产商品。
完整的类代码如下所示:
public class ProductList {
int index=0;
Product[] productList=new Product[6];
//生产者的生产活动
public synchronized void push(Product product){
//如果产库满了
while(index==productList.length){
System.out.println(" "+product.getProducedBy()+"is waitting");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//继续生产产品
productList[index]=product;
index++;
System.out.println(" "+product.getProducedBy()+"生产了:"+product);
//
notifyAll();
System.out.println(" "+product.getProducedBy()+"sent a notifyAll()");
}
//消费者的消费活动
public synchronized Product pop(String consumeName){
while(index==0){
System.out.println(" "+consumeName+"is waitting");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//继续消费产品
index--;
Product product=productList[index];
product.consume(consumeName);
System.out.println(index+" "+product.getConsumedBy()+"消费了"+product);
notifyAll();
System.out.println(" "+product.getConsumedBy()+"sent a notifyAll()");
return product;
}
}
(3)、生产者类
该类是生产者线程类,它包含了一个仓库对象,它的主函数run()中使用while(true)循环,表明不停地在生产。生产产品调用push()加入仓库,每生产一个产品后就会休眠一个随机时间。
public class Producer implements Runnable {
String name;
ProductList ps = null;
Producer(ProductList ps, String name) {
this.ps = ps;
this.name = name;
}
public void run() {
while (true) {
Product product = new Product(name);
ps.push(product);
try {
Thread.sleep((int) (Math.random() * 300));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
(4)、消费者类
该类是消费者线程类,它包含了一个仓库对象,它的主函数run()中使用while(true)循环,表明不停地在消费。消费产品调用pop()从仓库中取出商品,每消费一个产品后就会休眠一个随机时间。
public class Consumer implements Runnable {
String name;
ProductList ps=null;
public Consumer(String name, ProductList ps) {
this.name = name;
this.ps = ps;
}
@Override
public void run() {
while(true){
ps.pop(name);
try {
Thread.sleep((int) (Math.random()*300));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
(5)、最后来一个测试类
下面新建一个测试类,首先创建一个产品仓库ProductList的对象ps,然后根据该仓库创建两个生产者px和py,并创建3个消费者
ca、cb、cc。
public class ProducerConsumer {
public static void main(String[] args){
ProductList ps=new ProductList();
Producer px=new Producer(ps,"生产者x");
Producer py=new Producer(ps,"生产者y");
Consumer ca=new Consumer(ps,"消费者a");
Consumer cb=new Consumer(ps,"消费者b");
Consumer cc=new Consumer(ps,"消费者c");
new Thread(px).start();
new Thread(py).start();
new Thread(ca).start();
new Thread(cb).start();
new Thread(cc).start();
}
}
(6)、运行结果
启动这5个线程,这两个生产者就会不停地生产商品,消费者也会不停地消费商品,运行的结果如一下所示:
6 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
5 消费者B 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者B
消费者B sent a notifyAll().
4 消费者C 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者C
消费者C sent a notifyAll().
3 消费者C 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者C
消费者C sent a notifyAll().
2 消费者B 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者B
消费者B sent a notifyAll().
3 消费者B 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者B
消费者B sent a notifyAll().
4 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
5 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
4 消费者C 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者C
消费者C sent a notifyAll().
3 消费者C 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者C
消费者C sent a notifyAll().
2 消费者A 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者A
消费者A sent a notifyAll().
1 消费者A 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者A
消费者A sent a notifyAll().
2 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
1 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
0 消费者A 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者A
消费者A sent a notifyAll().
1 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
2 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
3 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
4 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
3 消费者C 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者C
消费者C sent a notifyAll().
4 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
3 消费者A 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者A
消费者A sent a notifyAll().
2 消费者A 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者A
消费者A sent a notifyAll().
3 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
2 消费者C 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者C
消费者C sent a notifyAll().
3 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
4 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
3 消费者C 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者C
消费者C sent a notifyAll().
4 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
3 消费者B 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者B
消费者B sent a notifyAll().
2 消费者B 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者B
消费者B sent a notifyAll().
1 消费者B 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者B
消费者B sent a notifyAll().
2 消费者A 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者A
消费者A sent a notifyAll().
1 消费者A 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者A
消费者A sent a notifyAll().
2 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
3 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
2 消费者A 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者A
消费者A sent a notifyAll().
3 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
4 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
3 消费者C 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者C
消费者C sent a notifyAll().
2 消费者C 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者C
消费者C sent a notifyAll().
1 消费者A 消费了: 产品, 生产者 = 生产者Y, 消费者 = 消费者A
消费者A sent a notifyAll().
0 消费者B 消费了: 产品, 生产者 = 生产者X, 消费者 = 消费者B
消费者B sent a notifyAll().
3 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
4 生产者Y 生产了: 产品, 生产者 = 生产者Y, 消费者 = N/A
生产者Y sent a notifyAll().
5 生产者X 生产了: 产品, 生产者 = 生产者X, 消费者 = N/A
生产者X sent a notifyAll().
..........
从结果来看,仓库中的产品数量在0和6之间徘徊,如果为0,则消费者等待;如果为6,则生产者等待。
生产者每生产一件商品,都会让仓库中的商品数量增加一件,会通知消费者来消费商品。
消费者侮消费一件商品,都会让仓库中的商品数量减少一件,会通知生产者来生产商品。
生产者和消费者之间共用的就是商品仓库这一个公共资源。使用该例很好的展示了资源的锁定与同步过程。