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();
    	}
       
    }
    

    運行結果

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