No9.生产者与消费者问题

知识点:

    1. 生产者和消费者问题的产生。

    2.Object类对多线程的产生。

具体内容:

      问题的引出:

          生产者和消费者指的是两个不同的线程类对象,操作同一资源的情况。具体的操作流程如下。

  1.  生产者负责生产数据,消费者负责取走数据。
  2.  生产者每生产完一组数据之后,消费者就去走一组数据。

现在假设要生产的数据如下:

  •      第一组数据:title=雷锋,content=好学生一枚;
  •      第二组数据:title=雷人的动物,content=草泥马;

package 多线程;

class Info{
	private String title;
	private String content;
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	
}
 
class Productor implements Runnable{
     private Info info;
     public Productor(Info info){
    	 this.info = info;
     }
	@Override
	public void run() {
		for(int x=0;x<100;x++)
			if(x%2==0){ //偶数
				this.info.setTitle("雷锋!");
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				this.info.setContent("好学生一枚!");
			}else{
				this.info.setTitle("雷人的动物!");
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				this.info.setContent("草泥马!");
			}
		
	}
	
}
class Customer implements Runnable{
    private Info info;
    public Customer(Info info){
    	this.info=info;
    }
	@Override
	public void run() {
		for(int x=0;x<100;x++){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(this.info.getTitle()+"-"+this.info.getContent());
		}
	}
	
}
public class T {
	public static void main(String args[]){
		Info info = new Info();
		new Thread(new Productor(info)).start();
		new Thread(new Customer(info)).start();
	}
	

}

运行结果:

现在实际上通过以上的代码可以发现两个严重问题:

  • 数据错位,发现不再是一个所需要的完整数据;
  • 数据重复取出,数据重复设置。
package 多线程;

class Info{
	private String title;
	private String content;
	public synchronized void set(String title,String content){
		this.title = title;
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.content = content;
	}
	public synchronized void get(){
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(this.title+"-"+this.content);
	}
}
 
class Productor implements Runnable{
     private Info info;
     public Productor(Info info){
    	 this.info = info;
     }
	@Override
	public void run() {
		for(int x=0;x<100;x++)
			if(x%2==0){ //偶数
				this.info.set("王惊雷","好学生一枚");			
			}else{
				this.info.set("可爱的动物","草泥马");
			}	
	}
}
class Customer implements Runnable{
    private Info info;
    public Customer(Info info){
    	this.info=info;
    }
	@Override
	public void run() {
		for(int x=0;x<100;x++){
			this.info.get();
		}
	}	
}
public class T {
	public static void main(String args[]){
		Info info = new Info();
		new Thread(new Productor(info)).start();
		new Thread(new Customer(info)).start();
	}
	

}

此时数据的错位问题得到了很好的解决,但是重复操作的问题更加严重了(大部分现实输出是:王惊雷,可爱动物出现太少)

解决重复问题:

    如果想要实现整个代码的操作,必须加入等待与唤醒机制。在Object类里面专门提供有处理方法。

  • 等待:public final void wait() throws InterruptedException;
  •  唤醒第一个等待线程: public final void notify ();
  • 唤醒全部等待线程,那个优先级高就先执行 :public final void notifyAll();
  • package 多线程;
    
    class Info{
    	private String title;
    	private String content;
    	private boolean flag = true;
    	//flag = true:表示可以生产,但是不可以取走
    	//flag = false:表示可以取走,但是不可以生产
    	public synchronized void set(String title,String content){
    	    //重复进入到set()方法里面,发现不能够生产,所以要等待
    		if(this.flag == false){
    			try {
    				super.wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		this.title = title;
    		try {
    			Thread.sleep(200);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		this.content = content;
    		this.flag=false;  //修改生产标记
    		super.notify();   //唤醒其他等待线程
    	}
    	public synchronized void get(){
    		//还没生产
    		if(this.flag == true){
    			try {
    				super.wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		try {
    			Thread.sleep(100);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println(this.title+"-"+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 x=0;x<100;x++)
    			if(x%2==0){ //偶数
    				this.info.set("王惊雷","好学生一枚");			
    			}else{
    				this.info.set("可爱的动物","草泥马");
    			}	
    	}
    }
    class Customer implements Runnable{
        private Info info;
        public Customer(Info info){
        	this.info=info;
        }
    	@Override
    	public void run() {
    		for(int x=0;x<100;x++){
    			this.info.get();
    		}
    	}	
    }
    public class T {
    	public static void main(String args[]){
    		Info info = new Info();
    		new Thread(new Productor(info)).start();
    		new Thread(new Customer(info)).start();
    	}
    	
    
    }
    

    面试题:请解释sleep()和wait()的区别?

  • Sleep()是Thread类定义的方法,wait()是Object类定义的方法;

  • Sleep()可以设置休眠时间,时间一到自动唤醒,而wait()需要等待notify()进行唤醒。

总结:这是一个经典的多线程处理模型,掌握它属于一个个人能力的提升,同时可以更加理解Object类的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值