Java并发基础:Queue

苦逼菜狗程序猿,用来总结和备忘,大家勿喷。

目录

jdk有两套实现(都是继承自接口Queue):

ConcurrentLinkedQueue(无阻塞无界队列)的用法

BlockingQueue(阻塞队列接口)的用法

模拟阻塞队列

主要队列的基本使用


jdk有两套实现(都是继承自接口Queue):

ConcurrentLinkedQueue(高性能并发Queue,无锁的方式实现的,性能好于BlockingQueue)

BlockingQueue(阻塞队列接口)

ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。

LinkedBlockingQueue:一个由链表结构组成的无界阻塞队列。

PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。

DealyQueue:一个带有延时时间的队列

SynchronousQueue:一个不存储元素的阻塞队列。

ConcurrentLinkedQueue(无阻塞无界队列)的用法

add() 和offer() 都是添加元素(非阻塞队列两个方法没有多大区别)

poll() 取出头元素并删除头元素

peek()取出元素但不删除

BlockingQueue(阻塞队列接口)的用法

offer(anObject)非阻塞添加元素,返回true和false

offer(E e, long timeout, TimeUnit unit) 指定时间内添加元素,如果添加成功返回true,不成功返回false

put(E e) 阻塞添加元素。如果队列没有空间,会一直阻塞到有空间添加元素为止

poll(long timeout, TimeUnit unit)指定时间内取出原属,取出元素返回true,否则返回false

take()阻塞取出队中的首位元素,如果队列内无元素会一直阻塞到有元素再继续

drainTo() 一次性取出队列中所有可用元素(也可以指定个数),通过改方法可以获取数据效率

模拟阻塞队列

  1. 队列代码
    package org.cc;
    
    import java.util.Stack;
    
    public class MyBlockQuene<T> {
          private Stack<T> stack;
          // push的锁
          private final static Object pushLock = new Object();
          // pop的锁
          private final static Object popLock = new Object();     
    	  public MyBlockQuene(){
    		  stack=new Stack<T>();
    	  }
    	  private static  int MAX_SIZE=3;
    	  //插入元素
    	  public  void push(T t){
    		  if(stack.size()>=3)
    			  lockPush();
    		  else{
    			  stack.push(t) ;
    			  unLockPop();
    		  }
    	  }
    	  //取出元素
    	  public T pop(){
    		  T  t= stack.pop();
    		 if(stack.size()<3)
    			 unLockPush();
    		 if(stack.size()==0)
    			 lockPop();
    		 return t;
    		 
    	  }
    	  public void unLockPush(){
    		  synchronized (pushLock) {
    			  pushLock.notify();
    		  }
    	  }
    	  public void lockPush(){
    		  synchronized (pushLock) {
    			  try {
    				  pushLock.wait();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		  }
    	  }
    	  public void unLockPop(){
    		  synchronized (popLock) {
    			  popLock.notify();
    		  }
    	  }
    	  public void lockPop(){
    		  synchronized (popLock) {
    			  try {
    				popLock.wait();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		  }
    	  }
    }
    

     

  2. 调用代码
    package org.cc;
    
    public class UseMyBlockingQueue {
    	   public static void main(String[] args) throws InterruptedException {
    		   final MyBlockingQueue  queue=new MyBlockingQueue<String>(3);
    		   queue.put("a");
    		   queue.put("b");
    		   queue.put("c");
    		   Thread t1=new Thread(new Runnable() {
    			
    			public void run() {
    				queue.put("e");
    				queue.put("f");
    			}
    		   });
    		   Thread t2=new Thread(new Runnable() {				
    				public void run() {
    					try {
    						Thread.sleep(1000);
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    					
    					queue.take();
    					try {
    						Thread.sleep(1000);
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    					queue.take();
    				}
    			   });
    		   t1.start();
    		   try {
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		   t2.start();
    	   }
    }
    

     

  3. 调用结果
    容容器中添加了一个元素a
    容容器中添加了一个元素b
    容容器中添加了一个元素c
    容器中取出了一个元素a
    容容器中添加了一个元素e
    容器中取出了一个元素b
    容容器中添加了一个元素f
    从结果可以看出添加3个之后必须有容器被取出之后才能继续添加元素

主要队列的基本使用

  1. ConcurrentLinkedQueue
    		//无阻塞无界队列
            ConcurrentLinkedDeque<String>  clq=new ConcurrentLinkedDeque<String>();
            clq.add("a");
            //无阻塞队列add和offer没有区别。都是添加元素
            clq.offer("b");
            clq.offer("c");
            System.out.println("clq容器当前长度:"+clq.size());
          //从头部取出元素,并在容器中移除元素
            System.out.println("poll从头部取出元素,并在容器中移除元素:"+clq.poll());
            System.out.println("clq容器当前长度:"+clq.size());
            System.out.println("peek从头部取出元素,但不移除元素:"+clq.peek());
            System.out.println("clq容器当前长度:"+clq.size());

    运行结果
    clq容器当前长度:3
    poll从头部取出元素,并在容器中移除元素:a
    clq容器当前长度:2
    peek从头部取出元素,但不移除元素:b
    clq容器当前长度:2
     

  2. ArrayBlockingQueue和LinkedBlockingQueue
     

            //基于数组的阻塞有界队列ArrayBlockingQueue
        	//基于链表的阻塞无界队列LinkedBlockingDeque
        	//两者用法相似,LinkedBlockingDeque将不在演示
            ArrayBlockingQueue<String>  abq=new ArrayBlockingQueue<String>(3);
            abq.add("a");
            abq.add("b");
            abq.add("c");
            System.out.println("offer会返回是否添加成功:"+abq.offer("f", 2, TimeUnit.SECONDS));  
            ArrayBlockingQueue<String>  abq1=new ArrayBlockingQueue<String>(3);
            abq.drainTo(abq1, 2);
            for(Iterator iterator=abq1.iterator(); iterator.hasNext();){
            	System.out.println((String)iterator.next());
            }

    运行结果
    offer会返回是否添加成功:false
    取出元素:a
    取出元素:b

  3. SynchronousQueue(不存元素的阻塞队列。必须先取再添加)
     

        	//不能直接添加元素,否则会报错,必须现有去元素方法
        	//Exception in thread "main" java.lang.IllegalStateException: Queue full
        	//sq.add("f");
        	new Thread(()->{    
    				try {
    					System.out.println("取出元素:"+sq.take());
    				} catch (Exception e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
        	}).start();
        	new Thread(()->{
    			System.out.println("添加元素是否成功:"+sq.add("f"));
    
        	}).start();

    运行结果
    添加元素是否成功:true
    取出元素:f

  4. PriorityBlockingQueue优先级阻塞队列
    注:插入或取出后队列都不会对整体重新排序只保证每次取出来是按照Comparable接口的实现取出优先级最高的
     

    package org.cc;
    
    /**
     * 实现Compareble接口
     * @author Machenike
     *
     */
    public class PriorityNode  implements Comparable<PriorityNode>{
    	private Integer id;
    	private String name;
    	public PriorityNode(Integer id,String name){
    		this.id=id;
    		this.name=name;
    	}
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	@Override
    	public int compareTo(PriorityNode o) {
    		return id>o.id?1:(id==o.id?0:-1);
    	}
    	@Override
    	public String toString() {
    		// TODO Auto-generated method stub
    		return id+":"+name;
    	}
    }
    
    	PriorityBlockingQueue<PriorityNode>  pbq=new PriorityBlockingQueue();
    
        	pbq.add(new PriorityNode(2,"name3"));
        	pbq.add(new PriorityNode(3,"name3"));
        	pbq.add(new PriorityNode(4,"name4"));
        	pbq.add(new PriorityNode(1,"name1"));
        	System.out.println(pbq.toString());
    		System.err.println("0 容器为: " + pbq);
    		System.err.println("1 获取元素: " + pbq.take().getId());
    		System.err.println("1 容器为: " + pbq);
    		System.err.println("2 获取元素: " + pbq.take().getId());
    		System.err.println("2 容器为: " + pbq);
    		System.err.println("3 获取元素: " + pbq.take().getId());
    		System.err.println("3 容器为: " + pbq);
    		System.err.println("4 获取元素: " + pbq.take().getId())

  5. DelayQueue延时队列
    元素需要继承java.util.concurrent.Delayed接口
    模拟订单自动取消功能

    package org.cc;
    
    import java.util.concurrent.Delayed;
    import java.util.concurrent.TimeUnit;
    
    public class Order  implements Delayed{
    	private Integer id;
    	private String name;
        private long endTime;//订单自动取消时间
    
    	public Order(Integer id, String name,long endTime) {
    		this.id = id;
    		this.name = name;
    		this.endTime=endTime;
    	}
        private final  TimeUnit timeUnit=TimeUnit.SECONDS;
    	public Integer getId() {
    		return id;
    	}
    
    	public void setId(Integer id) {
    		this.id = id;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	@Override
    	public int compareTo(Delayed o) {
    		Order w = (Order)o;
    		return this.getDelay(timeUnit) - w.getDelay(timeUnit) > 0 ? 1 : 0;
    
    	}
    
    	@Override
    	public long getDelay(TimeUnit unit) {
    		// TODO Auto-generated method stub
    		return endTime-System.currentTimeMillis();
    	}
    
    }
    
    package org.cc;
    
    import java.util.concurrent.DelayQueue;
    
    public class User  implements Runnable{
       private DelayQueue<Order>  dq=new DelayQueue<>();
       //下单
       public void  preOrder(Integer id,String name,long endTime){
    	   Order  o=new Order(id,name,endTime);
    	   dq.add(o);
    	   System.out.println("已创建订单:"+name+",请尽快付款。");
       }
       public void orderCancel(Order o) {
    	   System.out.println("你的订单"+o.getName()+"已自动取消!");
    	   
       }
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		while(true){
    			try {
    				orderCancel(dq.take());
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}		
    	}
    	public static void main(String[] args) {
    		User user=new User();				
    		user.preOrder(2, "订单二", 1000+System.currentTimeMillis());
    		user.preOrder(3, "订单三", 2000+System.currentTimeMillis());
    		user.preOrder(1, "订单一", 3000+System.currentTimeMillis());
    		new Thread(user).start();
    	}
       
    }
    

    运行结果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章