在线程操作中有一个经典的案例程序,即生产者和消费者问题,生产者不断生产,消费者不断取走生产者生产的产品。
生产者生产出信息后将其放到一个区域中,消费者从此区域中取出数据,但是本程序牵扯到线程运行的不确定性,所以会存在两点问题:
(1)假设生产者线程刚向数据存储空间添加了信息的名称,还没有加入该信息的内容,程序就切换到了消费者线程,消费者线程将把信息的名称和上一个信息的内容联系到一起
(2)生产者放了若干次的数据,消费者才开始取数据,或者是,消费者取完一个数据后,还没等到生产者放入新的数据,又重复取出已取过的数据。
一、程序的基本实现
因为程序中不断生产的是信息,而消费者不断取出的也是信息,所以定义一个保存信息的类:Info.java
class Info {
private String name = "JAVA";//信息名称,指定默认值
private String content = "LANGUAGE";//信息内容,指定默认值
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getContent(){
return content;
}
public void setContent(String content){
this.content = content;
}
}
Info 类的组成非常简单,只包含了用于保存信息名称的 name 属性 和用于保存信息内容的 content 属性,因为生产者和消费者要操作同一个空间的内容,所以生产者和消费者分别实现 Runnable 接口,并接收 Info 类的应用。
二、生产者
class Producer implements Runnable{//定义生产者线程
private Info info = null;//保存 Info 引用
public Producer(Info info){//通过构造方法设置 info 属性内容
this.info = info;//为 info 属性初始化
}
public void run(){//覆写 run()方法
boolean flag = false;//定义标记位
for(int i=0;i<10;i++){
if (flag){//如果为 TRUE,则设置第一个信息
this.info.setName("JAVA_1");//设置信息名称
try{
Thread.sleep(10);//加入延迟10
}catch (InterruptedException e){
e.printStackTrace();
}
this.info.setContent("LANGUAGE_1");//设置信息内容
flag = false;//修改标记位
}else {//如果为false,则设置第2 个信息
this.info.setName("JAVA_2");
try{
Thread.sleep(10);//加入延迟10
}catch (InterruptedException e){
e.printStackTrace();
}
this.info.setContent("LANGUAGE_2");
flag = true;//修改标记位
}
}
}
}
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
在生产者的构造方法中传入了 Info 类的实例化对象,然后在 run() 方法中循环10次以产生信息的具体内容。
三、消费者
class Consumer implements Runnable{//定义消费者线程
private Info info = null;
public Consumer(Info info){
this.info = info;//通过构造方法设置 info 属性,为 info 属性初始化
}
public void run(){
for(int i=0;i<10;i++){
try{
Thread.sleep(20);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.info.getName() + " --> " + this.info.getContent());//取出信息
}
}
}
消费者线程类中也同样接收了一个 Info 对象的引用,并采用 10 此循环的方式信息并输出
注意这里消费者代码中,延迟设置为20,就是为了产生当生产者添加了信息的名称,还没有加入该信息的内容,程序就切换到了消费者线程,消费者线程将把信息和上一个信息的内容联系到一起
四、测试程序
public class ThreadCase {
public static void main(String[] args) {
Info i = new Info();
Producer pro = new Producer(i);//实例化生产者,传递 Info 引用
Consumer con = new Consumer(i);//实例化消费者,传递 Info 引用
new Thread(pro).start();//启动生产者线程
new Thread(con).start();//启动消费者线程
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9