说明
Java中,线程之间的通信主要是由java.lang.Object类提供的wait、notify和notifyAll这3个方法来完成:
①对象的wait方法被调用后,线程进入对象的等待队列中,并释放对象锁,其它线程可以竞争使用此对象锁;sleep方法使得一个线程进入睡眠状态,但是线程所占有的资源并没有释放。
②当对象的notify方法被调用,该方法会从对象的等待队列中随机取出一个线程来唤醒;notifyAll是唤醒等待队列中所有线程,这些线程会与其它正在执行的线程共同竞争对象锁。
③wait、notify和notifyAll这3个方法只能出现在synchronized作用的范围内。当多个线程等待同一对象,而它们等待等待的条件不同时,应该使用notifyAll方法。notifyAll会导致性能下降,因为不必要的线程也会被唤醒。而notify唤醒的线程有可能不是所期望的线程。
生产者与消费者问题
这里,将使用某类资源(用类Goods表示)的线程称为消费者Consumer,产生同类资源的线程称为Producer。要想使得Consumer和Producer能够协同工作,则它们应该遵循如下规则:
(1)只要缓冲区buffer有空间,生产者Producer就可向其中存放资源;当缓冲区buffer已满时,则让生产者Producer等待,放弃自己已获取的对象锁,进入等待队列;
(2)只要缓冲区中有资源可用,消费者Consumer就可以从buffer中取出资源;当buffer为空时,则让Consumer等待,放弃自己已获取的对象锁,进入等待队列;
(3)Producer和Consumer不能同时读、写buffer。所以对buffer进行操作的方法increase(生产资源)和decrease(消费资源)均需要使用synchronized进行同步。
/**
* Goods类,表示共享资源
*/
package com.hh.Producer.Consumer;
public class Goods {
private final int SIZE = 5;
private int buffer = 0;
/**
* 共享资源增加
*/
public synchronized int increase() {
if (buffer < SIZE) {
++buffer;
notify(); // 通知消费者可以消费
} else {
try {
wait(); // 生成者线程等待,直到消费者线程发出notify通知
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return buffer;
}
/**
* 共享资源减少
*/
public synchronized int decrease() {
if (buffer > 0) {
--buffer;
notify(); // 通知生产者可以生产
} else {
try {
wait(); // 消费者线程等待,直到生产者线程发出notify通知
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return buffer;
}
public int getGoodsSize() {
return SIZE;
}
}
/**
* Producer类,模拟生产者线程
*/
package com.hh.Producer.Consumer;
public class Producer implements Runnable {
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
int goodsCount = goods.increase();
if (goodsCount != goods.getGoodsSize()) {
System.out.println("生产者生产了一件商品,目前商品数:" + goodsCount);
} else {
System.out.println("商品已满,生产者等待");
}
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* Consumer类,模拟消费者
*/
package com.hh.Producer.Consumer;
public class Consumer implements Runnable {
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
int goodsCount = goods.decrease();
if (goodsCount != 0) {
System.out.println("消费者消费了一件商品,目前商品数:" + goodsCount);
} else {
System.out.println("商品已空,消费者等待");
}
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 测试生产者Producer与消费者Consumer线程之间的通信
*/
package com.hh.Producer.Consumer;
public class TestMain {
public static void main(String[] args) {
Goods goods = new Goods();
Producer producer = new Producer(goods);
Consumer consumer = new Consumer(goods);
new Thread(producer).start();
new Thread(consumer).start();
}
}
注意:是在共享资源Goods类中进行wait和notify操作,并不是在Producer或者Consumer类中。
对于这样的问题,一定要自己动手写示例代码,这样才能较好的理解线程之间的通信问题。