Thread学习(十)无缓冲队列synchronousQueue,优先级队列PriorityBlockingQueue

本文深入探讨了SynchronousQueue与PriorityBlockingQueue的工作原理及特性,包括它们的内部结构、不同模式下的行为表现以及如何使用这些队列来实现线程间的高效通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BlockingQueue

synchronousQueue学习

SynchronousQueue是无界的,是一种无缓冲的阻塞队列,插入操作必须等待令一个线程取数据,反之亦然(SynchronousQueue是线程安全的,是阻塞的)。同步队列没有任何内部容量,甚至连一个队列的容量都没有。

公平模式: 
SynchronousQueue会采用公平锁,并配合一个FIFO队列来阻塞多余的生产者和消费者,从而体系整体的公平策略;

非公平模式(SynchronousQueue默认): 
SynchronousQueue采用非公平锁,同时配合一个LIFO队列来管理多余的生产者和消费者,而后一种模式,如果生产者和消费者的处理速度有差距,则很容易出现饥渴的情况,即可能有某些生产者或者是消费者的数据永远都得不到处理。

注意: 
(1)不能在同步队列上进行 peek,因为仅在试图要取得元素时,该元素才存在; 
(2)除非另一个线程试图移除某个元素,否则也不能(使用任何方法)添加元素; 
(3)不能迭代队列 
(4)该队列的头是尝试添加到队列的首个已排队插入线程的元素;如果没有这样的已排队线程,则没有可用于移除的元素并且pool方法将返回null 
(5)不允许 null 元素 
对于其他 Collection 方法(例如 contains)SynchronousQueue 作为一个空集合。 
(6)同步队列类似于传递性的设计,即一个线程中运行的对象要将某些信息/事件/任务传递给另一个线程中运行的对象-->同步 
(7)SynchronousQueue构造方法中可指定fairness的策略.如果fair,则等待线程以FIFO的顺序竞争访问;否则顺序是未指定的

  • SynchronousQueue方法

  • iterator() 永远返回空,因为里面没东西。

  • peek() 永远返回null。

  • put() 往queue放进去一个element以后就一直wait直到有其他thread进来把这个element取走。

  • offer() 往queue里放一个element后立即返回,如果碰巧这个element被另一个thread取走了,offer方法返回true,认为offer成功;否则返回false。

  • offer(2000, TimeUnit.SECONDS) 往queue里放一个element但是等待指定的时间后才返回,返回的逻辑和offer()方法一样。

  • take() 取出并且remove掉queue里的element(认为是在queue里的。。。),取不到东西他会一直等。

  • poll() 取出并且remove掉queue里的element(认为是在queue里的。。。),只有到碰巧另外一个线程正在往queue里offer数据或者put数据的时候,该方法才会取到东西。否则立即返回null。

  • poll(2000, TimeUnit.SECONDS) 等待指定的时间然后取出并且remove掉queue里的element,其实就是再等其他的thread来往里塞。

  • isEmpty()永远是true。

  • remainingCapacity() 永远是0。

  • remove()和removeAll() 永远是false。

注意:

(1)SynchronousQueue中没有空间,那么资源会会以最快的方式从生产者传递给消费者。 

(2)SynchronousQueue中维护着生产者和消费者线程队列,既然有队列,同样就有公平性和非公平性特性,公平性保证正在等待的插入线 程或者移除线程以FIFO的顺序传递资源

优先级队列PriorityBlockingQueue

PriorityBlockingQueue里面存储的对象必须是实现Comparable接口。队列通过这个接口的compare方法确定对象的priority。
规则是:当前和其他对象比较,如果compare方法返回负数,那么在队列里面的优先级就比较搞。
/**
 * 
 * 
 * QueenTest
 * 创建人:LBM
 * 时间:2016年11月29日-上午10:54:16 
 * @version 1.0.0
 *
 */
public class QueenTest {
	public static void main(String[] args) {
		PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<Task>();//创建一个优先级队列
		Task task1 = new Task();
		task1.setId(50);
		Task task2 = new Task();
		task2.setId(30);
		Task task3 = new Task();
		task3.setId(23);
		Task task4 = new Task();
		task4.setId(100);
//		像优先级队列中插入三个对象
		queue.put(task1);
		queue.put(task2);
		queue.put(task3);
		queue.put(task4);
		for (Task task : queue) {
			System.out.println("循环打印队列,查看队列顺序"+task.getId());
		}
			try {
				System.out.println("每次take后,查看队列顺序"+queue);
				System.out.println(queue.take().getId());
				System.out.println("每次take后,查看队列顺序"+queue);
				System.out.println(queue.take().getId());
				System.out.println("每次take后,查看队列顺序"+queue);
				System.out.println(queue.take().getId());
				System.out.println("每次take后,查看队列顺序"+queue);
				System.out.println(queue.take().getId());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	} 
}
//创建一个类实现Comparable方法
class Task implements Comparable<Task>{
	
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	//实现compareTo方法
	public int compareTo(Task task) {
		//当新元素的id小于旧元素的时候,优先级比较高
		if (task.id > this.id) {
			return -1;
		}
		else if (task.id < this.id) {
			return 1;
		}else {
			return 0;
		}
	}
	//重写toString方法
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return this.id+"";
	}
}
打印结果

我们知道我们插入的这组数据,数据最小的优先级越高,按照我们的想法,那我们存储的队列顺序应该是【23,30,50,100】但是真实的顺序却是【23,50,30,100】这是为什么呢 ?
原来在PriorityBlockingQueue内部只能保证第一个取出的元素是优先级最高的元素,并不能保证队列内部所有元素都按照优先级去排序,当我们每次take的时候,这个队列就会重新再内部调用compareTo方法,然后保证队首的那个元素是优先级最高的元素。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值