您的位置:首页 > 编程语言 > Java开发

Java基础复习:线程通信—生产者消费者改进

2013-05-21 15:20 751 查看
在前面的生产者消费者程序中,生产者一次生产的数据,消费者可以进行多次读取。显然,这并不符合我们的要求。对此,改进上述程序:

1)生产者生产一次数据,消费者取一次数据;

2)存储空间只能存放一对数据

在下面的代码中我们会用到:

Java通过Object类的 wait \ notify \ nofifyall 这几个方法来实现线程间的通信。

wait: 告诉当前线程放弃监视器并进入睡眠状态,知道其他线程进入同一监视器并调用notify为之。

notify: 唤醒同一对象监视器中调用wait的第一个线程。用于类似饭馆有一个空位后通知所有等候就餐的骨科中的第一位可以入座的情况。

notifyall:

唤醒同一对象监视器中调用wait的所有线程,且有最高优先级的线程首先被唤醒并执行,用于类似某个不定期的培训班终于招生满额后,通知所有学员来上课的情况。

wait \ notify \ nofifyall 这三个方法只能在 synchronized 方法中调用,即线程必须要先得到该对象的锁旗标。

package day14;

/**
* 数据存储区,并设置了默认生产的内容
*
* @author well
*
*/
class Storage {
String name = "Tom";
String sex = "male";
/**
* 存储区的状态,无数据时为false,有数据时为true
*/
boolean sFull = false;

/**
* 放数据
*
* @param name
* @param sex
*/
public synchronized void put(String name, String sex) {
//当存储区有数据时等待
while(sFull){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.sex = sex;
sFull = true;//放完数据,设置数据区为满状态
notify();//唤醒等待队列的消费者进程
}

/**
* 取数据
*/
public synchronized void get() {
while(!sFull){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name + "," + sex);
sFull = false;//取走数据后,设置数据区为空
notify();//唤醒等待队列的生产者进程
}
}

/**
* 生产者进程
*
* @author well
*
*/
class Producer implements Runnable {
Storage s = null;

Producer(Storage s) {
super();
this.s = s;
}

@Override
public void run() {
int i = 0;
for (; i < 500; i++) {

if (i % 2 == 0) {
s.put("Lily", "female");
} else {
s.put("Tom", "male");
}

}
}

}

/**
* 消费者进程
*
* @author well
*
*/
class Consumer implements Runnable {
Storage s = null;

Consumer(Storage s) {
super();
this.s = s;
}

@Override
public void run() {
for (int i = 0; i < 500; i++) {
s.get();
}
}

}

public class PCDemo {
public static void main(String[] args) {
Storage s = new Storage();
new Thread(new Producer(s)).start();
new Thread(new Consumer(s)).start();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: