技术问答-10 java中的集合(5)-Queue

版权声明:本文为博主原创文章,未经博主允许不得转载,如需转载请在明显处标明出处! https://blog.csdn.net/qq_36291682/article/details/86678970

Queue

一、Queue是什么

Queue是一种队列结构集合,用来储存将要进行处理的元素,一般会以FIFO的方式排序元素,但这不是必须的。比如优先级队列就是一个例外,优先级队列是以元素的值来排序。但是无论怎么样,每个queue的实现都必须制定它的排序属性。queue通常不定义元素的equal和hashCode

二、Queue的实现

1. 非阻塞

  • LinkedList 实现了Queue和AbstractQueue

  • PriorityQueue
    PriorityQueue类 实质上维护了一个有序列表。加入到Queue中的元素根据他们天然排序(通过实现Comparable实现)或者根据传递给构造函数的Comparator实现来定位,它的增加操作不是原子操作,没有添加任何锁,所以它是线程不安全的。

  • ConcurrentLinkedQueue
    ConcurrentLinkedQueue是基于链接节点的、线程安全的队列,并发访问不需要同步,
    它是非阻塞队列,使用CAS非阻塞算法实现
    推荐看看
    1. 阻塞
    java.util.concurrent中加入了BlockingQueue接口和五个阻塞队列,它实质上就是一种带有一点扭曲的FIFO数据结构。不是立即从队列添加或者删除元素,线程操作阻塞,直到有空间或元素可用

  • ArrayBlockingQueue :一个由数组支持的有界队列

  • LinkedBlockingQueue:一个由链表节点支持的可选有界的队列(固定线程 使用的就是它)

  • PriorityBlockingQueue:一个由优先级堆支持的无界优先级队列

  • DelayQueue: 一个由优先级堆的、基于时间的调度队列 (定时线程 使用的就是它)

  • SynchronousQueue:一个利用BlockingQueue接口的简单聚集机制(缓存线程 使用的就是它)

三、方法
返回 方法 说明
boolean add(E) 添加元素,如果队列已满,抛出IllegalStateException
boolean offer(E) 与add一样,add就是调用的offer方法
E remove() 移除并返回队列头部元素,如果队列为空则抛出NoSuchElementException
E element() 返回队列头部元素,如果队列为空则抛出NoSuchElementException
E poll() 移除并返回队列头部元素,如果队列为空则返回null
E peek() 返回队列头部元素 如果队列为空返回null
void put(E) 添加一个元素 如果队列满了 则阻塞
E take() 移除并返回队列头部元素,如果队列为空 则阻塞
package along;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import com.mysql.jdbc.TimeUtil;
public class javaTest {
	public static void main(String[] args) { 
		//ArrayBlockingQueue 
		ArrayBlockingQueue<Integer> aq = new ArrayBlockingQueue<Integer>(10);
		for(int i=0;i<11;i++){
			//aq.add(i);
		}
		//java.lang.IllegalStateException: Queue full
		
		//LinkedBlockingQueue 无界  有界 
		LinkedBlockingQueue<Integer> lq1 = new LinkedBlockingQueue<Integer>();
		LinkedBlockingQueue<Integer> lq2 = new LinkedBlockingQueue<Integer>(10);
		
		//PriorityBlockingQueue
		PriorityBlockingQueue<Integer> pq = new PriorityBlockingQueue<Integer>();
		pq.add(2);pq.add(8);pq.add(1);pq.add(22);
		Integer i=null;
		while((i = pq.poll()) != null){
			System.out.println(i);
		}
		//1 2 8 22 按顺序排列 
		
		DelayQueue<DelayedTest> dq = new DelayQueue<DelayedTest>();
		//这里传入的参数是毫秒 他会转换成秒 再加上当前系统时间
		DelayedTest d1 = new DelayedTest(1, "111111111111111111111", 10000);
		DelayedTest d2 = new DelayedTest(2, "222222222222222222222", 20000);
		DelayedTest d3 = new DelayedTest(3, "333333333333333333333", 30000);
		dq.add(d1);
		dq.add(d2);
		dq.add(d3);
		try{
//			System.out.println(dq.take());//元素被添加到队列  10秒后输出
//			System.out.println(dq.take());//元素被添加到队列  20秒后输出
//			System.out.println(dq.take());//元素被添加到队列  30秒后输出
		}catch(Exception e){
			System.out.println("error");
		}

		//SynchronousQueue 这个东西很神奇  它的作用是如果想add一个元素进去 必须有take在等待 也就是如果生产想要push必须等待消费者的take
		SynchronousQueue<Integer> sq =new SynchronousQueue<>();
//		sq.add(12);//没有线程take这里是没有办法加进去的
		
	    new Thread(new Runnable() {
			public void run() {
				try{
					System.out.println("元素:"+sq.take());
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}).start();
	   
	    //主线程等待2秒钟
	    try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
	    new Thread(new Runnable() {
			public void run() {
				try{
					sq.add(1111);
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}).start();
	    
	    //但是用put不会报错 他会等着take操作  没有take他不会put成功
	    try {
			sq.put(1212);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} 
	    /**
	    * 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。
	    */
	    // SynchronousQueue 内部没有容量,但是由于一个插入操作总是对应一个移除操作,反过来同样需要满足。
        // 那么一个元素就不会再SynchronousQueue 里面长时间停留,一旦有了插入线程和移除线程,元素很快就从插入线程移交给移除线程。
	    //也就是说这更像是一种信道(管道),资源从一个方向快速传递到另一方 向。
	    //显然这是一种快速传递元素的方式,也就是说在这种情况下元素总是以最快的方式从插入着(生产者)传递给移除着(消费者),
	    //这在多任务队列中是最快处理任务的方式。
	    //在线程池里的一个典型应用是Executors.newCachedThreadPool()就使用了SynchronousQueue,
	    //这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程空闲了60秒后会被回收。
	}
}

猜你喜欢

转载自blog.csdn.net/qq_36291682/article/details/86678970
今日推荐