zoukankan      html  css  js  c++  java
  • 从头认识java-17.5 堵塞队列(以生产者消费者模式为例)

    这一章节我们来讨论一下堵塞队列。我们以下将通过生产者消费者模式来介绍堵塞队列。

    1.什么是堵塞队列?(摘自于并发编程网对http://tutorials.jenkov.com/java-concurrency/blocking-queues.html的翻译)

    当队列是空的时。从队列中获取元素的操作将会被堵塞,或者当队列是满时。往队列里加入元素的操作会被堵塞。

    试图从空的堵塞队列中获取元素的线程将会被堵塞,直到其它的线程往空的队列插入新的元素。相同。试图往已满的堵塞队列中加入新元素的线程相同也会被堵塞,直到其它的线程使队列又一次变得空暇起来,如从队列中移除一个或者多个元素。或者全然清空队列,下图展示了怎样通过堵塞队列来合作:



    2.特性

    (1)先进先出

    (2)线程同步


    3.以下结合生产者消费者模式来介绍堵塞队列的使用情况

    package com.ray.ch17;
    
    import java.util.concurrent.LinkedBlockingQueue;
    
    public class Test {
    
    	public static void main(String[] args) {
    		Basket basket = new Basket();
    		Thread thread1 = new Thread(new Chief(basket));
    		Thread thread2 = new Thread(new Customer(basket));
    		Thread thread3 = new Thread(new Customer(basket));
    		thread1.start();
    		thread2.start();
    		thread3.start();
    	}
    }
    
    class Cake {
    	private static int index = 0;
    	private final int id = index++;
    
    	public int getId() {
    		return id;
    	}
    
    	public Cake() {
    		System.out.println("生产了蛋糕,id:" + id);
    	}
    }
    
    class Chief implements Runnable {
    	private Basket basket = null;
    
    	public Chief(Basket basket) {
    		this.basket = basket;
    	}
    
    	public void makeCake() throws InterruptedException {
    		for (int i = 0; i < 20; i++) {
    			basket.put(new Cake());
    			System.out.println("如今框里面的蛋糕数量:" + basket.getQueueSize());
    			Thread.sleep(20);
    		}
    	}
    
    	@Override
    	public void run() {
    		try {
    			makeCake();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    
    }
    
    class Customer implements Runnable {
    	private Basket basket = null;
    
    	public Customer(Basket basket) {
    		this.basket = basket;
    	}
    
    	public void buyCake() throws InterruptedException {
    		System.out.println("消费了蛋糕,id:" + basket.take().getId());
    		System.out.println("如今框里面的蛋糕数量:" + basket.getQueueSize());
    	}
    
    	@Override
    	public void run() {
    		try {
    			for (int i = 0; i < 10; i++) {
    				buyCake();
    				Thread.sleep(100);
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    class Basket {
    	private LinkedBlockingQueue<Cake> queue = new LinkedBlockingQueue<Cake>(10);
    
    	public void put(Cake cake) throws InterruptedException {
    		queue.put(cake);
    	}
    
    	public Cake take() throws InterruptedException {
    		Cake cake = queue.take();
    		return cake;
    	}
    
    	public int getQueueSize() {
    		return queue.size();
    	}
    }
    

    输出:

    生产了蛋糕,id:0
    消费了蛋糕,id:0
    如今框里面的蛋糕数量:0
    如今框里面的蛋糕数量:0
    生产了蛋糕,id:1
    如今框里面的蛋糕数量:1
    消费了蛋糕,id:1
    如今框里面的蛋糕数量:0
    生产了蛋糕,id:2
    如今框里面的蛋糕数量:1
    生产了蛋糕,id:3
    如今框里面的蛋糕数量:2
    生产了蛋糕,id:4
    如今框里面的蛋糕数量:3
    消费了蛋糕,id:2
    如今框里面的蛋糕数量:2
    生产了蛋糕,id:5
    如今框里面的蛋糕数量:3
    消费了蛋糕,id:3
    如今框里面的蛋糕数量:2
    生产了蛋糕,id:6
    如今框里面的蛋糕数量:3
    生产了蛋糕,id:7
    如今框里面的蛋糕数量:4
    生产了蛋糕,id:8
    如今框里面的蛋糕数量:5
    生产了蛋糕,id:9
    如今框里面的蛋糕数量:6
    消费了蛋糕,id:4
    如今框里面的蛋糕数量:5
    消费了蛋糕,id:5
    如今框里面的蛋糕数量:4
    消费了蛋糕,id:6
    如今框里面的蛋糕数量:3
    消费了蛋糕,id:7
    如今框里面的蛋糕数量:2
    消费了蛋糕,id:8
    如今框里面的蛋糕数量:1
    消费了蛋糕,id:9
    如今框里面的蛋糕数量:0


    解释:

    (1)因为是生产者消费者模式,因此上面必须有生产者、消费者、篮子和消费的物品(蛋糕)这四个类。另一个Test測试类

    (2)在Cake类里面,我们使用static的index来记录每个Cake的id

    (3)在Basket类里面我们除了put和take方法,还放入一个getSize的方法来得到篮子里面如今有多少个Cake

    (4)生产者和消费者事实上仅仅有一个方法就是生产make或者buy,这里面须要注意的是两个地方,第一个是数量,因为我们上面使用的是堵塞队列。因此当生产的总数量大于消费的总数量,程序就会一直在wait,仅仅有等到下一个消费者来消费才会继续运行,反之,假设消费的数量大于生产的数量也会出现这样的情况;第二个是时间,我们须要依照实际的时间匹配关系来配对时间,假设生产大于消费,在出现生产一个消费一个,须要添加生产者,假设是消费大于生产。则依据实际需求来定。


    以下的代码须要等待,就是因为消费的总数大于生产的总数而出现的问题:

    package com.ray.ch17;
    
    import java.util.concurrent.LinkedBlockingQueue;
    
    public class Test {
    
    	public static void main(String[] args) {
    		Basket basket = new Basket();
    		Thread thread1 = new Thread(new Chief(basket));
    		Thread thread2 = new Thread(new Customer(basket));
    		Thread thread3 = new Thread(new Customer(basket));
    		thread1.start();
    		thread2.start();
    		thread3.start();
    	}
    }
    
    class Cake {
    	private static int index = 0;
    	private final int id = index++;
    
    	public int getId() {
    		return id;
    	}
    
    	public Cake() {
    		System.out.println("生产了蛋糕,id:" + id);
    	}
    }
    
    class Chief implements Runnable {
    	private Basket basket = null;
    
    	public Chief(Basket basket) {
    		this.basket = basket;
    	}
    
    	public void makeCake() throws InterruptedException {
    		for (int i = 0; i < 20; i++) {
    			basket.put(new Cake());
    			System.out.println("如今框里面的蛋糕数量:" + basket.getQueueSize());
    			Thread.sleep(200);
    		}
    	}
    
    	@Override
    	public void run() {
    		try {
    			makeCake();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    
    }
    
    class Customer implements Runnable {
    	private Basket basket = null;
    
    	public Customer(Basket basket) {
    		this.basket = basket;
    	}
    
    	public void buyCake() throws InterruptedException {
    		System.out.println("消费了蛋糕,id:" + basket.take().getId());
    		System.out.println("如今框里面的蛋糕数量:" + basket.getQueueSize());
    	}
    
    	@Override
    	public void run() {
    		try {
    			for (int i = 0; i < 20; i++) {
    				buyCake();
    				Thread.sleep(100);
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    class Basket {
    	private LinkedBlockingQueue<Cake> queue = new LinkedBlockingQueue<Cake>(10);
    
    	public void put(Cake cake) throws InterruptedException {
    		queue.put(cake);
    	}
    
    	public Cake take() throws InterruptedException {
    		Cake cake = queue.take();
    		return cake;
    	}
    
    	public int getQueueSize() {
    		return queue.size();
    	}
    }
    





    总结:这一章节我们通过生产者消费者模式来介绍了堵塞队列的特性。


    这一章节就到这里,谢谢。

    -----------------------------------

    文件夹


  • 相关阅读:
    Web探索之旅 | 第二部分第三课:框架和内容管理系统
    Web探索之旅 | 第二部分第二课:服务器语言
    Web探索之旅 | 第二部分第一课:客户端语言
    Web探索之旅 | 第一部分:什么是Web?
    C++探索之旅 | 第一部分第三课:你的第一个C++程序
    C++探索之旅 | 第一部分第二课:C++编程的必要软件
    Python探索之旅 | 第一部分第三课:初识Python的解释器
    C++探索之旅 | 第一部分第一课:什么是C++
    C#对接JAVA系统遇到的AES加密坑
    typescript入门,可以一起探讨提点意见互相学习。
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/7209527.html
Copyright © 2011-2022 走看看