1.生产者-消费者问题的产生
生产者和消费者指的是两个不同的线程类对象,操作同一资源的情况。具体操作情况如下。
1.生产者负责生产数据,消费者负责取走数据
2.生产者每生产完一组数据之后,消费者就要取走一组数据
第一组数据:title="sl",content="Good Student"
第二组数据:title=“动物”,content="sheep"
package TestDemo;
class Info{
String name;
String content;
/**
* @return the content
*/
public String getContent() {
return content;
}
/**
* @param content the content to set
*/
public void setContent(String content) {
this.content = content;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
class Productor implements Runnable{
private Info info;
public Productor(Info info){
this.info=info;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if(i%2==0){
this.info.setName("animal");
try {
Thread.sleep(100);
} catch (Exception e) {
//TODO: handle exception
}
this.info.setContent("sheep");
continue;
}
this.info.setName("sl");
try {
Thread.sleep(100);
} catch (Exception e) {
//TODO: handle exception
}
this.info.setContent("Good student");
}
}
}
class Customer implements Runnable{
private Info info;
public Customer(Info info){
this.info=info;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (Exception e) {
//TODO: handle exception
}
System.out.println(this.info.getName()+"===="+this.info.getContent());
}
}
}
public class TestDemo{
public static void main(String[] args){
Info info=new Info();
new Thread(new Productor(info)).start();//由于生产者消费者类都是Runnable子类,可以传入构造
new Thread(new Customer(info)).start();
}
}
结果
![](https://img.haomeiwen.com/i9003228/5a3839dfcc9be974.png)
![](https://img.haomeiwen.com/i9003228/b0b735957eaaf084.png)
发现了两个严重问题:
1.数据错位
2.数据重复取出,数据重复设置
1.解决数据错位问题
数据错位完全是因为非同步的操作所造成的,所以应该使用同步处理。并且两个数据要同时设置。同时取出。因而对set,get进行同步方法
package TestDemo;
class Info{
String name;
String content;
public synchronized void set(String name,String content){
this.name=name;
try {
Thread.sleep(200);
} catch (Exception e) {
//TODO: handle exception
}
this.content=content;
}
public synchronized void get(){
try {
Thread.sleep(100);
} catch (Exception e) {
//TODO: handle exception
}
System.out.println(this.name+"==="+this.content);
}
}
class Productor implements Runnable{
private Info info;
public Productor(Info info){
this.info=info;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if(i%2==0){
this.info.set("animal", "sheep");
continue;
}
this.info.set("sl", "Good student");
}
}
}
class Customer implements Runnable{
private Info info;
public Customer(Info info){
this.info=info;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
this.info.get();
}
}
}
public class TestDemo{
public static void main(String[] args){
Info info=new Info();
new Thread(new Productor(info)).start();//由于生产者消费者类都是Runnable子类,可以传入构造
new Thread(new Customer(info)).start();
}
}
此时,数据错位问题得到了解决,但是重复问题更加严重了。
![](https://img.haomeiwen.com/i9003228/2c51bd4a9f538ad5.png)
然后我们解决重复问题:
如果要想实现整个代码的操作,必须加入等待与唤醒机制,在Object类里面有专门的处理方法
2.Object类对多线程的支持
Object类中有如下方法:
等待:public final void wait() throws InterruptedException
唤醒第一个等待线程:public final void notify();
唤醒全部等待线程,哪个优先级高,唤醒哪个:
public final void notifyAll();
解决重复问题:修改info方法
package TestDemo;
class Info{
String name;
String content;
private boolean flag=true;
//flag为true表示可以生产,但是不能取走
//flag为false表示可以取走但是不能生产
public synchronized void set(String name,String content){
//如果重复进行set方法
if(this.flag==false){
try {
super.wait();//让线程等待
} catch (Exception e) {
//TODO: handle exception
}
}
this.name=name;
try {
Thread.sleep(200);
} catch (Exception e) {
//TODO: handle exception
}
this.content=content;
this.flag=false;//修改生产标记
super.notify();//唤醒其它等待线程
}
public synchronized void get(){
if(this.flag==true){
try {
super.wait();
} catch (Exception e) {
//TODO: handle exception
}
}
try {
Thread.sleep(100);
} catch (Exception e) {
//TODO: handle exception
}
System.out.println(this.name+"==="+this.content);
this.flag=true;
super.notify();
}
}
class Productor implements Runnable{
private Info info;
public Productor(Info info){
this.info=info;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if(i%2==0){
this.info.set("animal", "sheep");
continue;
}
this.info.set("sl", "Good student");
}
}
}
class Customer implements Runnable{
private Info info;
public Customer(Info info){
this.info=info;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
this.info.get();
}
}
}
public class TestDemo{
public static void main(String[] args){
Info info=new Info();
new Thread(new Productor(info)).start();//由于生产者消费者类都是Runnable子类,可以传入构造
new Thread(new Customer(info)).start();
}
}
![](https://img.haomeiwen.com/i9003228/bfa44f92e04a8376.png)
成功了。
面试题:请解释sleep与wait区别:
sleep()是Thread类定义的方法,wait()是Object类定义的方法
sleep()可以设置休眠时间,时间一到自动唤醒,wait需要notify方法来唤醒。
总结
生产者-消费者模型是一个非常经典的多线程处理模型。
网友评论