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

Java基础----生产者消费者问题改进版

2014-12-30 18:06 351 查看
package cn.itcast_07;

public class Student {
private String name;
private int age;
private boolean flag; // 默认情况是没有数据,如果是true,说明有数据

public synchronized void set(String name, int age) {
// 如果有数据,就等待
if (this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

// 设置数据
this.name = name;
this.age = age;

// 修改标记
this.flag = true;
this.notify();
}

public synchronized void get() {
// 如果没有数据,就等待
if (!this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

// 获取数据
System.out.println(this.name + "---" + this.age);

// 修改标记
this.flag = false;
this.notify();
}
}


package cn.itcast_07;

public class SetThread implements Runnable {

private Student s;
private int x = 0;

public SetThread(Student s) {
this.s = s;
}

@Override
public void run() {
while (true) {
if (x % 2 == 0) {
s.set("林青霞", 27);
} else {
s.set("刘意", 30);
}
x++;
}
}
}


package cn.itcast_07;

public class GetThread implements Runnable {
private Student s;

public GetThread(Student s) {
this.s = s;
}

@Override
public void run() {
while (true) {
s.get();
}
}
}


package cn.itcast_07;

/*
* 分析:
* 		资源类:Student
* 		设置学生数据:SetThread(生产者)
* 		获取学生数据:GetThread(消费者)
* 		测试类:StudentDemo
*
* 问题1:按照思路写代码,发现数据每次都是:null---0
* 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
* 如何实现呢?
* 		在外界把这个数据创建出来,通过构造方法传递给其他的类。
*
* 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
* 		A:同一个数据出现多次
* 		B:姓名和年龄不匹配
* 原因:
* 		A:同一个数据出现多次
* 			CPU的一点点时间片的执行权,就足够你执行很多次。
* 		B:姓名和年龄不匹配
* 			线程运行的随机性
* 线程安全问题:
* 		A:是否是多线程环境		是
* 		B:是否有共享数据		是
* 		C:是否有多条语句操作共享数据	是
* 解决方案:
* 		加锁。
* 		注意:
* 			A:不同种类的线程都要加锁。
* 			B:不同种类的线程加的锁必须是同一把。
*
* 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
* 如何实现呢?
* 		通过Java提供的等待唤醒机制解决。
*
* 等待唤醒:
* 		Object类中提供了三个方法:
* 			wait():等待
* 			notify():唤醒单个线程
* 			notifyAll():唤醒所有线程
* 		为什么这些方法不定义在Thread类中呢?
* 			这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
* 			所以,这些方法必须定义在Object类中。
*
* 最终版代码中:
* 		把Student的成员变量给私有的了。
* 		把设置和获取的操作给封装成了功能,并加了同步。
* 		设置或者获取的线程里面只需要调用方法即可。
*/
public class StudentDemo {
public static void main(String[] args) {
//创建资源
Student s = new Student();

//设置和获取的类
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s);

//线程类
Thread t1 = new Thread(st);
Thread t2 = new Thread(gt);

//启动线程
t1.start();
t2.start();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: