java阻塞隊列數據操作詳解

阻塞隊列

隊列是一種只允許在標的前端進行刪除操作,而在表的藕斷進行插入操作的線性表。阻塞隊列和一班隊列的不同之處在於阻塞隊列是阻塞的,這裏的阻塞指的是操作隊列的線程的一種狀態。在阻塞隊列中,線程阻塞有如下兩種情況。

消費者阻塞

在隊列爲空時,消費者端的線程都會被自動阻塞(掛起),直到有數據放入隊列,消費者線程會被自動喚醒並消費數據。

生產者阻塞

在隊列已滿且沒有可用空間時,生產者端的線程都會被自動阻塞(掛起),直到隊列中有空的位置騰出,線程會被自動喚醒並生產數據。
阻塞隊列的主要操作
阻塞隊列的主要操作 有插入操作和移除操作。插入操作有add(e),offer(e),put(e),offer(e,time,unit),移除操作有remove(),pull()

插入操作

  1. public abstract boolean add(E paramE): 將指定的元素插入隊列中,在成功時返回true,如果當前沒有可用的空間,則拋出IlegalStateException。如果元素師null,則拋出NullPointException異常。JDK源碼的實現如下:

    		public boolean add(E e){
    		
    		//添加一個數據,如果成功,則返回true
    		if(offer(e))
    		return true;
    		//如果失敗返回異常
    		else
    		throw new IllegalStateException("Queue full");
    		}
    			
    
  2. public abstract boolean offer(E paramE): 將指定的元素插入隊列中,在成功時返回true,如果當前沒有可用的空間,則返回false。JDK源碼的實現如下:

    				public boolean offer(E e){
    				checkNotNull(e);
    				final ReentranLock lock = this.lock;
    				lock.lock();//獲取鎖try
    				try{
    				if(count == items.length)
    				//如果隊列滿了,則返回false
    				return false;
    				else{
    				enqueue(e);//如果隊列有空間,則將元素加入隊列中
    				return true;
    						}
    					}finally{
    					lock.unlock();
    					}
    				}
    
  3. offer(E o,long timeout, TimeUnit unit):將指定的元素插入隊列中,可以設定等待的時間,如果在設定的等待時間內仍不能像隊列中加入元素,則返回false。

  4. public abstract void put(E paramE)throws InterruptedException:將指定的元素插入隊列中,如果對烈烈已經滿了,則阻塞,等待可用的隊列空間的釋放,直到有可用的隊列空間釋放且插入成功爲止,JDK源碼的實現如下

    		 public void put(E e)throws InterruptedException {
    		 		
    				checkNotNull(e);
    						
    				final ReentrantLock lock =this.lock;
    				
    				lock.lockInterruptibly();
    				
    				try{
    				
    				while(count == items.length)//阻塞等待可用空間的釋放
    				
    				notFull.await();
    				
    				enqueue(e);//將元素加入隊列中
    				
    				}finally{
    				
    				lock.lock();
    				
    				}
    			}
    		
    

獲取數據操作

  1. poll();取走隊列隊首的對象,如果取不到數據,則返回null。JDK源碼的實現如下:
    		public E poll(){
    			
    			final ReenTranLock lock= this.lock;
    			
    			lock.lock();
    		
    			try{
    			//如果獲取不到數據count == 0 ,則返回null 
    			return (count ==0 )? null : dequeue();
    			
    			}finally{
    			
    			lock.unlock();//釋放鎖
    			
    			}
    		
    		}
    
  2. poll(long timeout, TimeUnit unit):取走隊列隊首的對象,如果在指定的時間內隊列有數據可取,則返回隊列中的數據,否則等待一定時間,在等待超時並且沒有數據可取時,返回null。
  3. take():取走隊列隊首的對象,入股哦隊列爲空,則進入阻塞狀態等待,直到隊列有心的數據被加入,在集市去除新加入的數據,JDK源碼的實現如下:
    		public E take() throws InterruptedException{
    			final ReentrantLock lock = this.lock;
    			lock.lockInterruptibly();//獲取獨佔鎖
    			try{
    			//如果隊列爲空,則進入阻塞狀態,直到能取到數據爲止
    			while(count==0{
    			notEmpty.await();
    			return dequeue();//取出元素}
    				finally{
    			lock.lock();
    					}
    				}
    			}
    		}
    
  4. drainTo(Collection collection): 一次性從隊列中批量獲取所有可用的數據對象,同事可以指定獲取數據的個數,通過該方法可以提升獲取數據的效率,避免多次頻繁操作引起的隊列鎖定。JDK源碼的實現如下:
    		public int drainTo(Collection<? super E> c,int maxElemenets){
    			checkNotNull(c);
    			if(c == this)
    				throw new IllegalArgumentException();
    			if(maxElemenet <= 0)
    			 return 0;
    			 final Object[] items = this.items;
    			 final ReentrantLock lock = this.lock;
    			// 獲取鎖操作lock.loc看();
    			try{
    				int n =Math.min(maxElemnent, count)//獲取隊列中指定個數的元素
    				int take = takeIndex;
    				int i = 0try{
    			while(i < n){
    					@SuppressWarnings("unchecked")
    				 	E x = (E) items[take];
    		 			c.add(x);
    					 items[take]=null;
    					 if (++take == items.length)
    			 			take =0;
    					 i++;		
    				}
    			return n;
    			
    			}finally{
    			//Restore inveriants even if c.add() threw// 如果在drainTo過程中有新的數據加入,則處理該數據
    			if(i>0{
    			count -=i;
    			takeIndex = take;
    			if( itrs !=null){
    			if(count ==0)
    				itrs.queueIsEmpty();
    				else if( i > take)
    				itrs.takeIndexWrapped();
    				
    				}
    				for(;i>0&& lock.hasWaiters(notFull);i--)
    					notFull.signal();//喚醒等待的生產者線程
    				}
    			}
    		}finally{
    				lock.unlock(;//釋放鎖
    				}
    		}
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章