* 生产者消费者模式:
*
* Student类:
* 公共的字段:姓名和年龄(学生数据)
* SetThread类:生产者线程
* 产生学生数据
* GetThread类:消费者线程
* 消费学生数据
*
*
* StudentDemo类:主线程(用户线程): 开启生产者线程和消费者线程!
*
* 问题1:消费者所在的线程和生产者所在的线程操作不是同一个资源对象
* null---0
*
*
*
* 在刚才基础上优化:t1线程:不断产生数据,t2(消费者线程)不断消费数据
* 在SetThread以及GetThread加入while循环
*
*
* 问题2:
* 1)同一个打印多次
* 线程在执行的,抢占CPU执行权,如果抢占到CPU的执行权,
* CPU一点点时间片可以让该I线程执行多次
* 2)发现姓名和年龄不符
* 线程的执行具有随机性
*
* 针对刚才这个程序,解决线程安全问题:
*
* 检验线程安全问题的标准是什么?
* 1)是否为多线程环境
* 2)是否有共享数据
* 3)是否有多条对共享数据操作
*
* 使用同步机制:synchronized同步代码块解决3)
* 将多条语句对共享数据的操作包裹起来!
*
* 继续优化:现在想让这个数据依次打印,而不是打印一片数据
* "hello",24
* "world",39
* ..
* ..
*
* 引入Java中等待唤醒机制!
*
* 生产者线程:判断是否有数据,没有数据,等待产生数据
* 消费者线程:判断是否有数据,如果有数据,等待消费掉
*
* 问题:产生死锁!
* 生产者线程,产生数据了,等待消费数据
* 消费者线程,消费完数据,等待生产数据
*
*
*
*
* 面试题:
* 1)sleep()和wait()方法的区别
*
* 区别1): 来源不同
* sleep()是Thread类中方法
* wait()是Object类中方法:需要使用锁对象调用的
*
* 2) 调用方法的时候是否释放锁
* sleep(long millis):线程睡眠多少毫秒数据(期间,线程是暂停状态)
* wait():线程等待,调用该方法,会立即释放锁对象!利用wait方法会释放锁对象,
* 然后使用锁对象调用notify(),来完成Java中等待唤醒机制!
*
* 3)共同点:wait和方法sleep()都会可能出现中断异常! InterruptedException
*
*
*
* 2)wait()和notify()这些方法为什么不定义Thread类中,而是在Object类中呢?
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();
}
}
//生产者资源类
/*
*
*
* */
public class SetThread implements Runnable {
//声明一个学生遍历
private Student s ;
public SetThread(Student s) {
this.s = s ;
}
//定义一个统计变量
private int x = 0 ;
@Override
public void run() {
//t1线程(生产者线程)
while(true) {
//同步代码块
synchronized(s) {
if(s.flag) {
//如果没有数据,
//等待产生数据
try {
s.wait(); //立即释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x % 2== 0) { //x= 0
s.name = "柯发兴" ;
s.age = 24 ;
}else { //x = 1
s.name = "高圆圆" ;
s.age = 39 ;
}
x ++;
//修饰标记:
s.flag = true ;//有数据了
//通知对方线程消费数据
s.notify();
}
}
//产生学生对象,生产数据
// Student s = new Student() ;
}
}
public class Student {
String name;
int age;
boolean flag ;//判断学生存在数据,默认false,不存在;true表示存在数据
}
//消费者资源类
public class GetThread implements Runnable {
//成员变量
private Student s ;
public GetThread(Student s) {
this.s = s ;
}
@Override
public void run() {
//不断消费数据
while(true) {
synchronized(s) {
//消费者判断如果有数据,先消费掉
if(!s.flag) {
try {
s.wait();//调用wati()会立即释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.name+"---"+s.age) ;
//修饰标记:
s.flag = false ;//没有数据类
//通知生产线程产生数据
s.notify();
}
}
}
}