Java隊列

隊列(queue),先進先出(First in first out,FIFO)。

堆棧(stack),後進先出(Last in first out,LIFO)。

      Java中有Stack這個類,但是不推薦使用。通常使用Deque來完成隊列和堆棧的功能。

      Deque是一個線性表接口,可以兩端進行元素的插入和刪除。Deque是“Double ended Queue”的縮寫,Deque讀音[dɛk] 。使用Deque接口提供的方法就可以完成隊列“先進先出”和堆棧“後進先出”的功能:

隊列

offer(E e) --- 向隊列尾加入元素

E poll() --- 獲取隊列頭部元素,並從隊列中刪去

堆棧

push(E e) --- 向堆棧中壓入元素

E pop() --- 獲取棧頂元素,並從堆棧中刪除

 

Deque是個接口,其實現類有:

  • ArrayDeque,使用“數組”存儲數據
  • LinkedList,使用“鏈表”存儲數據
  • ConcurrentLinkedDeque,線程安全的LinkedList

數據檢索多的用ArrayDeque;數據需要頻繁插入、更新,則用LinkedList;多線程操作使用ConcurrentLinkedDeque。

代碼示例:

1: Deque<String> queue = new LinkedList<String>();
2: queue.offer("data1");    //隊列尾部加入元素
3: queue.offer("data2");
4: queue.offer("data3");
5: System.out.println(queue.poll());    //取得隊首元素,並從隊列中刪去
6: 
7: Deque<String> stack = new LinkedList<String>();
8: stack.push("element1");    //向棧頂壓入元素
9: stack.push("element2");
10: stack.push("element3");
11: System.out.println(queue.pop());    //取得棧頂元素,並從棧頂刪去

 

非阻塞無界隊列

ConcurrentLinkedQueue

 

public static void main(String[] args) throws InterruptedException {
        ConcurrentLinkedQueue queue=new ConcurrentLinkedQueue();
        queue.add(1);//內部調用offer
        queue.offer(1);
        queue.remove();//如果隊裏爲空會報java.util.NoSuchElementException
        queue.peek();//拿隊列元素 但不刪除
        queue.poll();獲取隊列元素並刪除如果沒有則是null
    }

阻塞隊列

阻塞隊列 指的是像隊列添加元素 如果滿了則阻塞等待隊列容器有空間再往裏面添加元素。或則 隊列爲空往容器裏面取元素 則阻塞等待隊列裏面有元素取出‘

方法。

JDK7提供了7個阻塞隊列

  • ArrayBlockingQueue :一個由數組結構組成的有界阻塞隊列。
  • LinkedBlockingQueue :一個由鏈表結構組成的有界阻塞隊列。
  • PriorityBlockingQueue :一個支持優先級排序的無界阻塞隊列。
  • DelayQueue:一個使用優先級隊列實現的無界阻塞隊列。
  • SynchronousQueue:一個不存儲元素的阻塞隊列。
  • LinkedTransferQueue:一個由鏈表結構組成的無界阻塞隊列。
  • LinkedBlockingDeque:一個由鏈表結構組成的雙向阻塞隊列。

常用方法

添加

boolean add 如果隊列滿了add則拋出異常

boolean offer 如果隊列滿了 可以設置阻塞時間

void put 如果隊列滿了則一直阻塞

獲取隊列元素並移除

Integer remove  如果隊列爲空 則拋出異常

Integer poll   如果隊列爲空可設置阻塞時間

void take  如果隊列爲空 一直阻塞

獲取隊列元素不移除

element  如果隊列爲空拋出異常

 peek 如果隊列爲空則獲的null

ArrayBlockingQueue

使用數組實現 先進先出的隊列。提供2個構造參數,默認不保證訪問者公平的訪問隊列,就是調用添加方法 默認不是按先阻塞的線程 先存。  或者移除 不是按先阻塞的線程先獲取並移除 可以通過ArrayBlockingQueue fairQueue = new  ArrayBlockingQueue(1000,true); 設置爲true保證公平性

LinkedBlockingQueue

使用鏈表實現 跟ArrayBolckingQueue的區別則是

ArrayBolckingQueue:

  1.一個是生產者和消費者使用的是同一把鎖。

  2.初始化必須指定大小

       3.插入時直接將對象插入

LinkedBlockingQueue:

  1.則是使用生產者使用一把鎖 消費者使用一把鎖

       2.可以不指定容器大小 但是最大值是Integer.MAX_VALUE

       3.插入時將對象轉爲Node插入

PriorityBlockingQueue

 擁有優先級排序的無界隊列。需要實現comparator接口。

public class Student implements Comparable<Student> {
    public Integer age;
    public  Student(Integer age){
        this.age=age;
    }
    @Override
    public int compareTo(Student stu) {
        if(age < stu.age)
        {
            return -1;
        }else
        {
            if(age > stu.age)
            {
                return 1;
            }else
            {
                return 0;
            }
        }
    }
}
PriorityBlockingQueue<Student> queue=new PriorityBlockingQueue<Student>();
        queue.add(new Student(1));
        queue.add(new Student(3));
        queue.add(new Student(5));
        queue.add(new Student(0));
        System.out.println(queue.poll().age);
        System.out.println(queue.poll().age);
        System.out.println(queue.poll().age);
        System.out.println(queue.poll().age);

輸出

0
1
3
5

DelayQueue

支持延時的無界阻塞隊列 需要實現delay接口

public class Message implements Delayed {
    private final long expire;  //到期時間
    private final String msg;   //數據

    public Message( long expire, String msg) {
        this.expire = expire;
        this.msg = msg;
    }

    /**
     * 需要實現的接口,獲得延遲時間   用過期時間-當前時間
     * @param unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.expire - System.currentTimeMillis() , TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed other) {
        return (int) (this.getDelay(TimeUnit.MILLISECONDS) -other.getDelay(TimeUnit.MILLISECONDS));
    }

    public long getExpire() {
        return expire;
    }

    public String getMsg() {
        return msg;
    }
}
public static void main(String[] args) throws InterruptedException {
        DelayQueue<Message> queue=new DelayQueue<Message>();

        Calendar nowTime = Calendar.getInstance();
        nowTime.add(Calendar.MINUTE, 1);
        Message message=new Message(nowTime.getTime().getTime(),"哈哈哈");
        queue.add(message);
        nowTime = Calendar.getInstance();
        nowTime.add(Calendar.MINUTE, 3);
         message=new Message(nowTime.getTime().getTime(),"哈哈哈3");
        queue.add(message);
        nowTime = Calendar.getInstance();
        nowTime.add(Calendar.MINUTE, 2);
         message=new Message(nowTime.getTime().getTime(),"哈哈哈2");
        queue.add(message);
        while (true) {
          Message message1=   queue.take();
          System.out.println(message1.getMsg());
        }
    }

SynchronousQueue

  沒有容量的隊列。生產者生產立即推送給消費者

public static void main(String[] args) throws InterruptedException {
        SynchronousQueue<String> queue=new SynchronousQueue<String>();
        new Thread(new Runnable() {
            @Override
            public void run() {
                int i=0;
               while (true){
                   try {
                       Thread.sleep(1000);
                       queue.put(Integer.toString(i));
                   } catch (Exception e) {
                       e.printStackTrace();
                   }
                   i++;
               }
            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true){
                    try {
                        Thread.sleep(2000);
                        System.out.println(queue.take().toString());
                    } catch (Exception e) {
                        e.printStackTrace();
                    } {

                    }
                }

            }
        }).start();
    }

LinkedTransferQueue

LinkedTransferQueue是一個由鏈表結構組成的無界阻塞TransferQueue隊列。相對於其他阻塞隊列LinkedTransferQueue多了tryTransfer和transfer方法。

1. transfer(E e):若當前存在一個正在等待獲取的消費者線程,即立刻移交之;否則,會插入當前元素e到隊列尾部,並且等待進入阻塞狀態,到有消費者線程取走該元素。
     2. tryTransfer(E e):若當前存在一個正在等待獲取的消費者線程(使用take()或者poll()函數),使用該方法會即刻轉移/傳輸對象元素e;若不存在,則返回false,並且不進入隊列。這是一個不阻塞的操作。

LinkedBlockingDeque

LinkedBlockingDeque是一個由鏈表結構組成的雙向阻塞隊列。所謂雙向隊列指的你可以從隊列的兩端插入和移出元素。雙端隊列因爲多了一個操作隊列的入口,在多線程同時入隊時,也就減少了一半的競爭。相比其他的阻塞隊列,LinkedBlockingDeque多了addFirst,addLast,offerFirst,offerLast,peekFirst,peekLast等方法

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