生产者消费者模型是多线程同步的解决案例之一。生产者用于生产数据存放至缓冲区,也即仓库,而消费者用于消耗仓库中的数据,保证仓库的容量。
在生产者和消费者模型中,我们使用wait()和notify()方法控制生产者和消费者的生产与消费。当仓库已满时,控制生产者不再进行生产,当仓库已空,控制消费者不再进行消费。
在这里,我们需要注意的是wait()和notify()的使用方法。在一个线程中使用wait()方法使线程阻塞后,只能在另一个线程中调用notify()方法唤醒线程,当存在多个线程同时被阻塞,notify()只唤醒优先级最高的被阻塞线程,使用notifyAll()可唤醒全部线程。
为保证线程操作数据的安全,在使用wait()和notify()时要对线程进行同步。
我们以生产小球为例,生产者负责生产小球,消费者负责消耗小球,设置仓库容量为20。
小球
public class Ball {
int x,y;
Graphics g;
public Ball(int x,int y) {
this.x=x;
this.y=y;
}
public void DrawMe(Graphics g) {
this.g=g;
g.fillOval(x, y,50,50);
}
}
生产者线程
public class ProductionThread extends Thread{
int capacity;
Graphics g;
ArrayList<Ball> balls = new ArrayList();
public ProductionThread(int capacity,ArrayList<Ball> balls,Graphics g) {
this.capacity=capacity;
this.g=g;
this.balls=balls;
}
public void run() {
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(balls) {
g.setColor(Color.black);
g.fillRect(0, 0, 800, 800);
g.setColor(Color.red);
Random r = new Random();
int x=r.nextInt(800);
int y = r.nextInt(800);
//System.out.println("x="+x+" y="+y);
Ball newball = new Ball(x,y);
balls.add(newball);
for(int j = 0;j<balls.size();j++) {
Ball ball = balls.get(j);
ball.DrawMe(g);
}
System.out.println("生产 一个球,库存:"+balls.size());
if(balls.size()>=capacity) {
try {
balls.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
balls.notify();
}
}
}
}
}
消费者线程
public class ConsumptionThread extends Thread{
int capacity;
Graphics g;
int i=0;
ArrayList<Ball> balls = new ArrayList();
public ConsumptionThread(int capacity,ArrayList<Ball> balls,Graphics g) {
this.capacity=capacity;
this.g=g;
this.balls=balls;
}
public void run() {
while(true) {
try {
Thread.sleep(150);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(balls) {
if(balls.size()>0) {
balls.remove(balls.size()-1);
System.out.println("消费一个球,库存="+balls.size());
}
if(balls.size()==0) {
try {
balls.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
balls.notify();
}
}
}
}
}
控制小球对象
public class PC{
public static void main(String[] args) {
PC pc = new PC();
pc.init();
}
public void init() {
JFrame jf = new JFrame();
jf.setTitle("画图");
jf.setSize(new Dimension(800,800));
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
ArrayList<Ball> balls = new ArrayList();
int Capacity=20;
int stock;
Graphics g = jf.getGraphics();
ProductionThread pt = new ProductionThread(Capacity,balls,g);
pt.start();
ConsumptionThread ct = new ConsumptionThread(Capacity,balls,g);
ct.start();
}
}
部分输出结果如下:
生产 一个球,库存:1
消费一个球,库存=0
生产 一个球,库存:1
生产 一个球,库存:2
消费一个球,库存=1
生产 一个球,库存:2
消费一个球,库存=1
生产 一个球,库存:2
生产 一个球,库存:3
消费一个球,库存=2