Java并发编程之阻塞队列

ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO(先进先出)原则对元素进行排序。

LinkedBlockingQueue:是一个基于链表结构的阻塞队列,此队列按FIFO(先进先出)排序元素,吞吐量通常高于ArrayBlockingQueue。

SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于SynchronousQueue。

 

 

阻塞队列的好处


在多线程领域:所谓阻塞,在某些情况下会挂起线程,一旦条件满足,被挂起的线程又会被自动唤醒。

 

为什么需要BlockingQueue

好处是我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为一切BlockingQueue都给你一手包办了。

在Concurrent包发布以前,在多线程环境下,我们每个程序员都必须去自己控制这些细节,尤其还要兼顾效率和线程安全,这会给我们的程序带来不小的复杂度。

 

 

阻塞队列的核心方法


方法类型

抛出异常

特殊值

阻塞

超时

插入

add(e)

offer(e)

put(e)

offer(e,time,unit)

移除

remove()

poll()

take()

poll(time,uni)

检查

element()

peek()

不可用

不可用

 

抛出异常

当阻塞队列满时,再往队列里add插入元素会抛出IllegalStateException: Queue full

当阻塞队列空时,再往队列里remove移除元素会抛出NoSuchElementException

当阻塞队列为空时,使用element判断第一个元素时抛出NoSuchElementException

特殊值

offer(),插入方法,成功true失败false

poll(),移除方法,成功返回出队列的元素,队列中没有元素就返回null

一直阻塞

当阻塞队列满时,生产者线程继续往队列里put元素,队列会一直阻塞,直到put或响应中断退出

当阻塞队列为空时,消费者线程试图从队列里take元素,队列会一直阻塞消费者线程,直到队列可用

超时退出

当阻塞队列满时,队列会阻塞生产者线程一定时间,超过时间后线程会退出

 

队列满时add

BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(1);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));

 

队列空时remove

BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(1);
//先进先出,清除最先进入的元素
blockingQueue.remove();

 

队列满时offer

BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(1);
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));

 

队列空时poll

BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(1);
System.out.println(blockingQueue.poll());

 

队列满时put

static BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(1);

创建两个线程分别为生产者和消费者

new Thread(new Runnable() {
	@Override
	public void run() {
		try {
                    System.out.println("开始");
			blockingQueue.put("a");
			blockingQueue.put("b");
                    System.out.println("结束");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
},"生产者").start();
		
new Thread(new Runnable() {
	@Override
	public void run() {
		try {
			Thread.sleep(10_000);
			blockingQueue.take();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
},"消费者").start();

上面的例子中,我们可以看到的现象是生产者线程打印”开始“到打印”结束“之间经历了10秒。

这是因为当生产者线程向队列中put一个b元素时,由于队列已满,因此发生了阻塞,

此时,进过10秒的休眠的消费者线程从线程中取出a元素,队列未满,生产者线程被唤醒,将b放入队列,程序结束。

 

 

SynchronousQueue队列


SynchronousQueue没有容量。

与其他BlockingQueue不同,SynchronousQueue是一个不存储元素的BlockingQueue。

每一个put操作必须要等待一个take操作,否则不能继续添加元素,反之亦然。

static BlockingQueue<String> blockingQueue=new SynchronousQueue();
new Thread(new Runnable() {
	@Override
	public void run() {
		try {
			blockingQueue.put("a");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
},"生产者").start();

new Thread(new Runnable() {
	@Override
	public void run() {
		try {
			System.out.println(blockingQueue.take());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
},"消费者").start();

只执行put或者只执行take方法,线程都会处于阻塞状态,因此put操作必须配合take操作。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值