等待唤醒机制,生产者消费者
测试类
package com.shujia.day19.waitdemo;
/*
等待唤醒机制:
共享数据:学生对象(name,age)
生产者线程:对学生对象进行赋值操作
消费者线程:对学生对象进行取值操作
为了观察更好的效果,我们可以让生产者赋值不同的信息
这时候出现了重复取值和姓名与年龄对应不上的情况
检测线程程序是否存在安全问题的三要素:
1、是否存在多线程环境?是 生产者和消费者
2、是否存在共享数据?是 student
3、是否存在多条语句操作共享数据?是
解决方案:
1、加入同步代码块
2、加入lock锁
虽然解决了线程安全的问题,但是结果并不是我们想要的结果,在生产者消费者模型中,消费一次应该通知生产者生产。等待唤醒机制。
注意:等待唤醒机制是建立线程安全的基础之上设置的。
*/
public class StudentDemo {
public static void main(String[] args) {
Student s = new Student();
ProductThread p1 = new ProductThread(s);
ConsumerThread c1 = new ConsumerThread(s);
p1.start();
c1.start();
}
}
生产者类
package com.shujia.day19.waitdemo;
public class ProductThread extends Thread{
private Student s;
private int i = 0;
public ProductThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s){
//应该先看一看数据有没有被消费,若被消费了,才赋新的值,通知消费者消费,若没有消费,等待消费者消费
if(s.getFlag()){
//若学生对象中flag成员变量值是true,生产就不会生产
//由多个线程共享且唯一的锁对象进行等待
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i%2==0){
s.setName("魏一民");
s.setAge(19);
}else {
s.setName("陈真");
s.setAge(18);
}
i++;
s.setFlag(true);
//赋值之后应该通知消费者进行消费数据
s.notify();
}
}
}
}
消费者类
package com.shujia.day19.waitdemo;
public class ConsumerThread extends Thread {
private Student s;
public ConsumerThread(Student s) {
this.s = s;
}
@Override
public void run() {
// Student s = new Student();
while (true) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s) {
//消费者消费数据之前,先判断数据有没有生产,若生产了,就取值打印,若没有生产,就等待,通知生产者生产
if (!s.getFlag()) {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.getName() + "-" + s.getAge());
s.setFlag(false);
//通知生产者赋值新的数据
s.notify();
}
}
}
}
学生类
package com.shujia.day19.waitdemo;
public class Student {
private String name;
private int age;
private boolean flag; // boolean类型的默认值在内存是false
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean getFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}