一,生产者与消费者
下面写一个生产窝头,消费窝头的例子来模拟生产者与消费者的情景,用面向对象的思维,下面分别有WoTou,Basket,Croduce,Customer几个对象.
窝头Wotou对象,有一个含义id的构造方法,重写了toString()方法
package com.remote3c.main;
public class Wotou {
private int id;
public Wotou(int id) {
super();
this.id = id;
}
public String toString(){
return "wotou : "+id;
}
}
篮子Basket对象,是整个例子的核心对象,有put()生产和set()消费两个方法,这两个方法分别用关键字Synchronized修饰,表示同步
package com.remote3c.main;
public class Basket {
int index = 0;
Wotou[] wotou = new Wotou[6];//假设篮子能装这么多个窝头
//生产窝头
public synchronized void put(Wotou w){
while(index ==wotou.length){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();
wotou[index]=w;
index++;
};
//消费窝头
public synchronized Wotou get(){
while(index==0){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();
index--;
return wotou[index];
}
}
生产者Produce,含义篮子的构造方法,调用篮子的put()方法往篮子里添加wotou
package com.remote3c.main;
import java.util.concurrent.TimeUnit;
public class Producer implements Runnable {
private Basket bt;
public Producer(Basket bt) {
this.bt = bt;
}
@Override
public void run() {
for(int i=0;i<20;i++){
Wotou wotou = new Wotou(i);
bt.put(wotou);
System.out.println("生产了------- :"+wotou);
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
消费者Customers,含义篮子的构造方法,调用篮子的get()方法从篮子里取wotou
package com.remote3c.main;
import java.util.concurrent.TimeUnit;
public class Customer implements Runnable {
private Basket bt;
public Customer(Basket bt) {
super();
this.bt = bt;
}
@Override
public void run() {
for(int i=0;i<20;i++){
Wotou wotou =bt.get();
System.out.println("消费了 :"+wotou);
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
测试程序
package com.remote3c.main;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
Basket basket =new Basket();
Producer producer =new Producer(basket);
Customer cusotmer=new Customer(basket);
new Thread(producer).start();
new Thread(cusotmer).start();
}
}
输出结果
生产了------- :wotou : 0
消费了 :wotou : 0
生产了------- :wotou : 1
生产了------- :wotou : 2
生产了------- :wotou : 3
生产了------- :wotou : 4
生产了------- :wotou : 5
生产了------- :wotou : 6
消费了 :wotou : 6
生产了------- :wotou : 7
消费了 :wotou : 7
生产了------- :wotou : 8
消费了 :wotou : 8
生产了------- :wotou : 9
生产了------- :wotou : 10
消费了 :wotou : 9
消费了 :wotou : 10
生产了------- :wotou : 11
生产了------- :wotou : 12
消费了 :wotou : 11
生产了------- :wotou : 13
消费了 :wotou : 12
生产了------- :wotou : 14
消费了 :wotou : 13
消费了 :wotou : 14
生产了------- :wotou : 15
消费了 :wotou : 15
生产了------- :wotou : 16
消费了 :wotou : 16
生产了------- :wotou : 17
消费了 :wotou : 17
生产了------- :wotou : 18
消费了 :wotou : 18
生产了------- :wotou : 19
消费了 :wotou : 19
消费了 :wotou : 5
消费了 :wotou : 4
消费了 :wotou : 3
消费了 :wotou : 2
消费了 :wotou : 1
二,wait()方法
1,wait()必须在同步控制块或方法内使用,否则运行时会报错。
2,wait()与sleep()最大的差别是,wait会释放锁,而sleep睡着了也抱着那把锁。
3,wait必须通过notify()或notifyAll()方法才能变为就绪状态
4,wai,notify()和notifyAll()都是基类Object的方法,因为这些方法操作的锁是所有对象的一部分,所以可以把wait()放进任何同步方法里,而不用担心这个类时继承了Thread还是实现了Runnable接口。