Java并发之阻塞队列

1.什么是阻塞队列?他和普通队列之间的区别?

阻塞队列与普通队列的区别在于当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列。

2.有哪些阻塞队列

juc包下提供了7个阻塞队列

1、ArrayBlockingQueue 数组结构组成的有界阻塞队列。
ArrayBlockingQueue是一个用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序。默认情况下不保证访问者公平的访问队列,所谓公平访问队列是指阻塞的所有生产者线程或消费者线程,当队列可用时,可以按照阻塞的先后顺序访问队列,即先阻塞的生产者线程,可以先往队列里插入元素,先阻塞的消费者线程,可以先从队列里获取元素。通常情况下为了保证公平性会降低吞吐量。

2、LinkedBlockingQueue一个由链表结构组成的有界阻塞队列
LinkedBlockingQueue是一个用链表实现的有界阻塞队列。此队列的默认和最大长度为Integer.MAX_VALUE。此队列按照先进先出的原则对元素进行排序。

3、PriorityBlockingQueue
PriorityBlockingQueue是一个支持优先级的无界队列。默认情况下元素采取自然顺序排列,也可以通过比较器comparator来指定元素的排序规则。元素按照升序排列。

4、DelayQueue
支持延时获取元素的无界阻塞队列,即可以指定多久才能从队列中获取当前元素

5、SynchronousQueue
不存储元素的阻塞队列,每一个put必须等待一个take操作,否则不能继续添加元素。并且他支持公平访问队列。

6、LinkedTransferQueue由链表结构组成的无界阻塞TransferQueue队列。相对于其他阻塞队列,多了tryTransfer和transfer方法

transfer方法

如果当前有消费者正在等待接收元素(take或者待时间限制的poll方法),transfer可以把生产者传入的元素立刻传给消费者。如果没有消费者等待接收元素,则将元素放在队列的tail节点,并等到该元素被消费者消费了才返回。

tryTransfer方法

用来试探生产者传入的元素能否直接传给消费者。,如果没有消费者在等待,则返回false。和上述方法的区别是该方法无论消费者是否接收,方法立即返回。而transfer方法是必须等到消费者消费了才返回。

7、LinkedBlockingDeque
LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列。所谓双向队列指的你可以从队列的两端插入和移出元素。双端队列因为多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。相比其他的阻塞队列,LinkedBlockingDeque多了addFirst,addLast,offerFirst,offerLast,peekFirst,peekLast等方法,以First单词结尾的方法,表示插入,获取(peek)或移除双端队列的第一个元素。以Last单词结尾的方法,表示插入,获取或移除双端队列的最后一个元素。另外插入方法add等同于addLast,移除方法remove等效于removeFirst。但是take方法却等同于takeFirst,不知道是不是Jdk的bug,使用时还是用带有First和Last后缀的方法更清楚。在初始化LinkedBlockingDeque时可以初始化队列的容量,用来防止其再扩容时过渡膨胀。另外双向阻塞队列可以运用在“工作窃取”模式中。

3.通过阻塞队列实现多生产者多消费者

import java.util.concurrent.ArrayBlockingQueue;

public class ProductConsumer {
	public static void main(String[] args) {
		Store store = new Store();
		new Product(1, store).start();
		new Product(2, store).start();
		new Product(3, store).start();
		new Consumer(1, store).start();
		new Consumer(2, store).start();
		new Consumer(3, store).start();
	}
}

class Product extends Thread {
	private Integer id;
	private Store store;

	public Product(Integer id, Store store) {
		this.id = id;
		this.store = store;
	}

	@Override
	public void run() {
		for (int i = 1; i < 100; i++) {
			store.produce(new Goods(Integer.toString(i),this.id), this.id);
			try {
				Thread.sleep(1500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

class Consumer extends Thread {
	private Integer id;
	private Store store;

	public Consumer(Integer id, Store store) {
		this.id = id;
		this.store = store;
	}

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			store.consume(this.id);
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

class Goods {
	private String id;
	private Integer productId;

	public Goods(String id, Integer productId) {
		this.id = id;
		this.productId = productId;
	}

	public String getId() {
		return productId+"-"+id;
	}

	public void setId(String id) {
		this.id = productId+"-"+this.id;
	}

}

class Store {
	private ArrayBlockingQueue queue = new ArrayBlockingQueue<>(10);

	private final int MAX_CAPACITY = 10;

	public void produce(Goods good, Integer productId) {
		try {
			queue.put(good);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(productId + "号生产者生产了" + good.getId() + "号商品,放入仓库中");
	}

	public Goods consume(Integer consumerId) {
		Goods good = null;
		try {
			good = queue.take();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(consumerId + "号消费者消费了" + good.getId() + "号商品");
		return good;
	}
}

运行结果如下:

2号消费者消费了1-1号商品
3号消费者消费了2-1号商品
1号消费者消费了3-1号商品
3号生产者生产了3-1号商品,放入仓库中
2号生产者生产了2-1号商品,放入仓库中
1号生产者生产了1-1号商品,放入仓库中
2号生产者生产了2-2号商品,放入仓库中
1号生产者生产了1-2号商品,放入仓库中
3号生产者生产了3-2号商品,放入仓库中
2号消费者消费了2-2号商品
3号消费者消费了3-2号商品
1号消费者消费了1-2号商品
3号生产者生产了3-3号商品,放入仓库中
1号生产者生产了1-3号商品,放入仓库中
2号生产者生产了2-3号商品,放入仓库中
3号生产者生产了3-4号商品,放入仓库中
1号生产者生产了1-4号商品,放入仓库中
2号生产者生产了2-4号商品,放入仓库中
1号消费者消费了3-3号商品
3号消费者消费了1-3号商品
2号消费者消费了2-3号商品
1号生产者生产了1-5号商品,放入仓库中
3号生产者生产了3-5号商品,放入仓库中
2号生产者生产了2-5号商品,放入仓库中

 

你可能感兴趣的:(Java阻塞队列)