• 《多线程操作之生产者消费者》(单生产单消费&多生产多消费)


    说明1:假设有一个放商品的盘子(此盘子只能放下一个商品)。生产者每次生产一个商品之后,放到这个盘子里,然后唤醒消费者来消费这个面包。消费者消费完这个商品之后,就唤醒生产者生产下一个商品。前提是,只有盘子里没有商品时,生产者才生产商品,只有盘子里有商品时,消费者才来消费。因此第一个程序是一个“单生产”  “单消费” 的问题。代码如下所示:

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    //描述资源  
    //资源属性:商品名称和编号 
    //行为:对商品名称赋值,获取商品
    class Resource{
    	
    	private String name;
    	private int count = 1;
    
    	// 定义标记
    	private boolean flag = false; //初始标记为假,表明盘子里没有商品(面包)
    
    	// 定义一个锁对象
    	private Lock lock = new ReentrantLock();
    
    	//获取锁上的Condition对象	
    	private Condition producer = lock.newCondition();//负责生产
    	private Condition consumer = lock.newCondition();//负责消费 
    
    	// 提供生产商品的方法
    	public void set(String name) {
    		lock.lock(); //获取锁
    		try {
    			while (flag) //当flag标记为真时,说明盘子里有商品(面包)此时生产者等待,否则,生产商品
    				try {
    					producer.await();
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			this.name = name + count;
    			count++;
    			System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);
    			flag = true;
    			// 唤醒一个消费者
    			consumer.signal();
    		} finally {//释放锁
    			lock.unlock();
    		}
    	}
    
    	//提供消费的方法
    	public void out() {
    		lock.lock(); //获取锁
    		try {
    			while (!flag) //当flag标记为假时,说明盘子里没有商品(面包),此时,消费者等待,否则,消费商品(面包)
    				try {
    					consumer.await();
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name);
    			flag = false;
    			//唤醒一个生产者
    			producer.signal();
    		} finally {//释放锁
    			lock.unlock();
    		}
    	}
    }
    
    // 描述生产者
    class Producer implements Runnable {
    	// 生产者一初始化就要有资源
    	private Resource r;
    
    	public Producer(Resource r) {
    		this.r = r;
    	}
    
    	@Override
    	public void run() {
    		while (true) {
    			r.set("面包");
    		}
    	}
    }
    
    // 描述消费者
    class Consumer implements Runnable {
    	// 消费者一初始化就要有资源
    	private Resource r;
    
    	public Consumer(Resource r) {
    		this.r = r;
    	}
    
    	@Override
    	public void run() {
    		while (true) {
    			r.out();
    		}
    	}
    }
    
    public class ProducerConsumer {
    	public static void main(String[] args) {
    		// 创建资源对象
    		Resource r = new Resource();
    
    		// 创建线程任务
    		Producer pro = new Producer(r);
    		Consumer con = new Consumer(r);
    
    		// 创建线程对象(两个生产者,两个消费者)
    		Thread t1 = new Thread(pro);
    		Thread t2 = new Thread(pro);
    		Thread t3 = new Thread(con);
    		Thread t4 = new Thread(con);
    
    		// 开启线程
    		t1.start();
    		t2.start();
    		t3.start();
    		t4.start();
    	}
    }
    

      运行结果如下图所示:(注意Ctrl+C结束程序)

    说明2:在多生产多消费问题中,我们假设有很多个盘子组成一个数组,生产者不停的生产商品(面包)往数组里面放,消费者不停的消费。当生产者判断已经所有盘子里都已经有面包时【注意,此处生产者判断所有盘子里都有面包,不是简单的判断生产的面包数目等于数组的长度这么简单,因为生产者在生产面包的同时,消费者也在消费面包,当生产者把生产的面包放到最后一个盘子里时,可能消费者已经消费了前面若干个面包了,所以此时并不满足所有盘子里都有面包。】生产者等待,唤醒一个消费者来消费。当消费者判断所有盘子里都没有面包时【注意:此处也不是简单的判断消费的面包数目等于数组长度这么简单,和上面的分析同理】消费者等待,唤醒一个生产者进行生产。多生产多消费的代码如下:

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    class BoundedBuffer {
       final Lock lock = new ReentrantLock();//锁
       final Condition notFull  = lock.newCondition(); //生产
       final Condition notEmpty = lock.newCondition(); //消费
    
       final Object[] items = new Object[100];//存储商品的容器。
       int putptr/*生产者使用的角标*/, takeptr/*消费者使用的角标*/, count/*计数器*/;
    
    	/*生产者使用的方法,往数组中存储商品*/
       public void put(Object x) throws InterruptedException {
         lock.lock(); //获取锁
         try {
           while (count == items.length) //判断计数器是否已到数组长度。满了。
             notFull.await();//生产就等待。
    
           items[putptr] = x; //按照角标将商品存储到数组中
    	   System.out.println(Thread.currentThread().getName()+"...生产者..."+items[putptr]+"--->"+count);
    		
           if (++putptr == items.length) //如果存储的角标到了数组的长度,就将角标归零。
    			putptr = 0;
           ++count;//计数器自增。
           notEmpty.signal();//唤醒一个消费者
         } finally {
           lock.unlock();
         }
       }
    
    	//消费者使用的方法
       public Object take() throws InterruptedException {
         lock.lock();
         try {
           while (count == 0) //如果计数器为0,说明没有商品,消费者等待。
             notEmpty.await();
           Object x = items[takeptr]; //从数组中通过消费者角标获取商品。
    
           if (++takeptr == items.length) //如果消费的角标等于了数组的长度,将角标归零。
    		   takeptr = 0;
           --count;//计数器自减。
    	   System.out.println(Thread.currentThread().getName()+"...消费者--->"+items[takeptr]+"..."+count);
           notFull.signal();//唤醒生产者。
           return x;
         } finally {
           lock.unlock();
         }
       } 
     }
     
    //生产者
    class Producer implements Runnable 
    {
    	//private int n = 1;
    	private BoundedBuffer b;
    	public Producer(BoundedBuffer b){
    		this.b = b;
    	}
    
    	public void run(){
    		while(true){
    			try{
    				b.put("面包");
    				//n++;
    			}catch(InterruptedException e){}
    			
    		}
    	}
    }
    
    //消费者
    class Consumer implements Runnable 
    {
    	private BoundedBuffer b;
    	public Consumer(BoundedBuffer b){
    		this.b = b;
    	}
    
    	public void run(){
    		while(true){
    			try{
    				b.take();
    			}catch(InterruptedException e){}
    			
    		}
    	}
    }
    
    //主函数
    public class ThreadDemo12
    {
    	public static void main(String args[]){
    		//创建资源对象
    		BoundedBuffer b = new BoundedBuffer();
    
    		//创建线程任务
    		Producer pro = new Producer(b);
    		Consumer con = new Consumer(b);
    
    		//创建线程对象
    		Thread t1 = new Thread(pro);
    		Thread t2 = new Thread(pro);
    		Thread t3 = new Thread(con);
    		Thread t4 = new Thread(con);
    
    		//开启线程
    		t1.start();
    		t2.start();
    		t3.start();
    		t4.start();
    	}
    }
    

      运行截图如下:

    欢迎留言交流!

  • 相关阅读:
    RegExp
    svn操作
    前端跨域请求
    UML
    excel 常用设置
    python中 cmp
    python global nonlocal
    python常见异常提示
    table边框和td的width失效
    display_css
  • 原文地址:https://www.cnblogs.com/sun-/p/10307878.html
Copyright © 2020-2023  润新知