91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中的5大隊列是什么

發布時間:2021-10-26 09:34:22 來源:億速云 閱讀:125 作者:iii 欄目:編程語言

這篇文章主要講解了“Java中的5大隊列是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java中的5大隊列是什么”吧!

阻塞隊列和非阻塞隊列

阻塞隊列(Blocking Queue)提供了可阻塞的 puttake 方法,它們與可定時的 offerpoll 是等價的。如果隊列滿了 put 方法會被阻塞等到有空間可用再將元素插入;如果隊列是空的,那么 take 方法也會阻塞,直到有元素可用。當隊列永遠不會被充滿時,put 方法和 take 方法就永遠不會阻塞。

Java中的5大隊列是什么  


我們可以從隊列的名稱中知道此隊列是否為阻塞隊列,阻塞隊列中包含 BlockingQueue 關鍵字,比如以下這些:

  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • ....... 
阻塞隊列功能演示

接下來我們來演示一下當阻塞隊列的容量滿了之后會怎樣,示例代碼如下:

import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;

public class BlockingTest {
    public static void main(String[] args) throws InterruptedException {
        // 創建一個長度為 5 的阻塞隊列
        ArrayBlockingQueue q1 = new ArrayBlockingQueue(5);
        
        // 新創建一個線程執行入列
        new Thread(() -> {
            // 循環 10 次
            for (int i = 0; i < 10; i++) {
                try {
                    q1.put(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(new Date() + " | ArrayBlockingQueue Size:" + q1.size());
            }
            System.out.println(new Date() + " | For End.");
        }).start();

        // 新創建一個線程執行出列
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    // 休眠 1S
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!q1.isEmpty()) {
                    try {
                        q1.take(); // 出列
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}
 

以上代碼的執行結果如下:

Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:1

Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:2

Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:3

Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:4

Mon Oct 19 20:16:12 CST 2020 | ArrayBlockingQueue Size:5

Mon Oct 19 20:16:13 CST 2020 | ArrayBlockingQueue Size:5

Mon Oct 19 20:16:14 CST 2020 | ArrayBlockingQueue Size:5

Mon Oct 19 20:16:15 CST 2020 | ArrayBlockingQueue Size:5

Mon Oct 19 20:16:16 CST 2020 | ArrayBlockingQueue Size:5

Mon Oct 19 20:16:17 CST 2020 | ArrayBlockingQueue Size:5

Mon Oct 19 20:16:17 CST 2020 | For End.

從上述結果可以看出,當 ArrayBlockingQueue 隊列滿了之后就會進入阻塞,當過了 1 秒有元素從隊列中移除之后,才會將新的元素入列。 

非阻塞隊列

非阻塞隊列也就是普通隊列,它的名字中不會包含 BlockingQueue 關鍵字,并且它不會包含 put 和 take 方法,當隊列滿之后如果還有新元素入列會直接返回錯誤,并不會阻塞的等待著添加元素,如下圖所示:

Java中的5大隊列是什么

非阻塞隊列的典型代表是 ConcurrentLinkedQueue 和 PriorityQueue。 

有界隊列和無界隊列

有界隊列:是指有固定大小的隊列,比如設定了固定大小的 ArrayBlockingQueue,又或者大小為 0 的 SynchronousQueue

Java中的5大隊列是什么

無界隊列:指的是沒有設置固定大小的隊列,但其實如果沒有設置固定大小也是有默認值的,只不過默認值是 Integer.MAX_VALUE,當然實際的使用中不會有這么大的容量(超過 Integer.MAX_VALUE),所以從使用者的角度來看相當于 “無界”的。

Java中的5大隊列是什么    

按功能分類

接下來就是本文的重點了,我們以功能來劃分一下隊列,它可以被分為:普通隊列、優先隊列、雙端隊列、延遲隊列、其他隊列等,接下來我們分別來看。 

1.普通隊列

普通隊列(Queue)是指實現了先進先出的基本隊列,例如 ArrayBlockingQueue 和 LinkedBlockingQueue,其中 ArrayBlockingQueue 是用數組實現的普通隊列,如下圖所示:

Java中的5大隊列是什么

LinkedBlockingQueue 是使用鏈表實現的普通隊列,如下圖所示:

Java中的5大隊列是什么  
 

常用方法

普通隊列中的常用方法有以下這些:

  • offer():添加元素,如果隊列已滿直接返回 false,隊列未滿則直接插入并返回 true;
  • poll():刪除并返回隊頭元素,當隊列為空返回 null;
  • add():添加元素,此方法是對 offer 方法的簡單封裝,如果隊列已滿,拋出 IllegalStateException 異常;
  • remove():直接刪除隊頭元素;
  • put():添加元素,如果隊列已經滿,則會阻塞等待插入;
  • take():刪除并返回隊頭元素,當隊列為空,則會阻塞等待;
  • peek():查詢隊頭元素,但不會進行刪除;
  • element():對 peek 方法進行簡單封裝,如果隊頭元素存在則取出并不刪除,如果不存在拋出 NoSuchElementException 異常。

注意:一般情況下 offer() 和 poll() 方法配合使用,put() 和 take() 阻塞方法配合使用,add() 和 remove() 方法會配合使用,程序中常用的是 offer() 和 poll() 方法,因此這兩個方法比較友好,不會報錯

接下來我們以 LinkedBlockingQueue 為例,演示一下普通隊列的使用:

import java.util.concurrent.LinkedBlockingQueue;

static class LinkedBlockingQueueTest {
    public static void main(String[] args) {
        LinkedBlockingQueue queue = new LinkedBlockingQueue();
        queue.offer("Hello");
        queue.offer("Java");
        queue.offer("中文社群");
        while (!queue.isEmpty()) {
            System.out.println(queue.poll());
        }
    }
}
 

以上代碼的執行結果如下:

Hello

Java

中文社群

 
2.雙端隊列

雙端隊列(Deque)是指隊列的頭部和尾部都可以同時入隊和出隊的數據結構,如下圖所示:

Java中的5大隊列是什么

接下來我們來演示一下雙端隊列 LinkedBlockingDeque 的使用:

import java.util.concurrent.LinkedBlockingDeque;

/**
  * 雙端隊列示例
  */
static class LinkedBlockingDequeTest {
    public static void main(String[] args) {
        // 創建一個雙端隊列
        LinkedBlockingDeque deque = new LinkedBlockingDeque();
        deque.offer("offer"); // 插入首個元素
        deque.offerFirst("offerFirst"); // 隊頭插入元素
        deque.offerLast("offerLast"); // 隊尾插入元素
        while (!deque.isEmpty()) {
            // 從頭遍歷打印
            System.out.println(deque.poll());
        }
    }
}
 

以上代碼的執行結果如下:

offerFirst

offer

offerLast

 
3.優先隊列

優先隊列(PriorityQueue)是一種特殊的隊列,它并不是先進先出的,而是優先級高的元素先出隊。

優先隊列是根據二叉堆實現的,二叉堆的數據結構如下圖所示:

Java中的5大隊列是什么

二叉堆分為兩種類型:一種是最大堆一種是最小堆。以上展示的是最大堆,在最大堆中,任意一個父節點的值都大于等于它左右子節點的值。


因為優先隊列是基于二叉堆實現的,因此它可以將優先級最好的元素先出隊。

接下來我們來演示一下優先隊列的使用:

import java.util.PriorityQueue;

public class PriorityQueueTest {
    // 自定義的實體類
    static class Viper {
        private int id; // id
        private String name; // 名稱
        private int level; // 等級

        public Viper(int id, String name, int level) {
            this.id = id;
            this.name = name;
            this.level = level;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getLevel() {
            return level;
        }

        public void setLevel(int level) {
            this.level = level;
        }
    }
    public static void main(String[] args) {
  PriorityQueue queue = new PriorityQueue(10, new Comparator<Viper>() {
            @Override
            public int compare(Viper v1, Viper v2) {
                // 設置優先級規則(倒序,等級越高權限越大)
                return v2.getLevel() - v1.getLevel();
            }
        });
        // 構建實體類
        Viper v1 = new Viper(1, "Java", 1);
        Viper v2 = new Viper(2, "MySQL", 5);
        Viper v3 = new Viper(3, "Redis", 3);
        // 入列
        queue.offer(v1);
        queue.offer(v2);
        queue.offer(v3);
        while (!queue.isEmpty()) {
            // 遍歷名稱
            Viper item = (Viper) queue.poll();
            System.out.println("Name:" + item.getName() +
                               " Level:" + item.getLevel());
        }
    }
}
 

以上代碼的執行結果如下:

Name:MySQL Level:5

Name:Redis Level:3

Name:Java Level:1

從上述結果可以看出,優先隊列的出隊是不考慮入隊順序的,它始終遵循的是優先級高的元素先出隊

 
4.延遲隊列

延遲隊列(DelayQueue)是基于優先隊列 PriorityQueue 實現的,它可以看作是一種以時間為度量單位的優先的隊列,當入隊的元素到達指定的延遲時間之后方可出隊。

Java中的5大隊列是什么  


我們來演示一下延遲隊列的使用:

import lombok.Getter;
import lombok.Setter;
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class CustomDelayQueue {
    // 延遲消息隊列
    private static DelayQueue delayQueue = new DelayQueue();
    public static void main(String[] args) throws InterruptedException {
        producer(); // 調用生產者
        consumer(); // 調用消費者
    }

    // 生產者
    public static void producer() {
        // 添加消息
        delayQueue.put(new MyDelay(1000, "消息1"));
        delayQueue.put(new MyDelay(3000, "消息2"));
    }

    // 消費者
    public static void consumer() throws InterruptedException {
        System.out.println("開始執行時間:" +
                DateFormat.getDateTimeInstance().format(new Date()));
        while (!delayQueue.isEmpty()) {
            System.out.println(delayQueue.take());
        }
        System.out.println("結束執行時間:" +
                DateFormat.getDateTimeInstance().format(new Date()));
    }

    static class MyDelay implements Delayed {
        // 延遲截止時間(單位:毫秒)
        long delayTime = System.currentTimeMillis();
        // 借助 lombok 實現
        @Getter
        @Setter
        private String msg;

        /**
         * 初始化
         * @param delayTime 設置延遲執行時間
         * @param msg       執行的消息
         */
        public MyDelay(long delayTime, String msg) {
            this.delayTime = (this.delayTime + delayTime);
            this.msg = msg;
        }

        // 獲取剩余時間
        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        // 隊列里元素的排序依據
        @Override
        public int compareTo(Delayed o) {
            if (this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS)) {
                return 1;
            } else if (this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS)) {
                return -1;
            } else {
                return 0;
            }
        }
        @Override
        public String toString() {
            return this.msg;
        }
    }
}
 

以上代碼的執行結果如下:

開始執行時間:2020-10-20 20:17:28

消息1

消息2

結束執行時間:2020-10-20 20:17:31

從上述結束執行時間和開始執行時間可以看出,消息 1 和消息 2 都正常實現了延遲執行的功能。

 
5.其他隊列

在 Java 的隊列中有一個比較特殊的隊列 SynchronousQueue,它的特別之處在于它內部沒有容器,每次進行 put() 數據后(添加數據),必須等待另一個線程拿走數據后才可以再次添加數據,它的使用示例如下:

import java.util.concurrent.SynchronousQueue;

public class SynchronousQueueTest {

    public static void main(String[] args) {
        SynchronousQueue queue = new SynchronousQueue();

        // 入隊
        new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                try {
                    System.out.println(new Date() + ",元素入隊");
                    queue.put("Data " + i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }).start();

        // 出隊
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                    System.out.println(new Date() + ",元素出隊:" + queue.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
 

以上代碼的執行結果如下:

Mon Oct 19 21:00:21 CST 2020,元素入隊

Mon Oct 19 21:00:22 CST 2020,元素出隊:Data 0

Mon Oct 19 21:00:22 CST 2020,元素入隊

Mon Oct 19 21:00:23 CST 2020,元素出隊:Data 1

Mon Oct 19 21:00:23 CST 2020,元素入隊

Mon Oct 19 21:00:24 CST 2020,元素出隊:Data 2

從上述結果可以看出,當有一個元素入隊之后,只有等到另一個線程將元素出隊之后,新的元素才能再次入隊。

感謝各位的閱讀,以上就是“Java中的5大隊列是什么”的內容了,經過本文的學習后,相信大家對Java中的5大隊列是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

合川市| 元朗区| 信宜市| 沿河| 西盟| 大方县| 喀喇沁旗| 元氏县| 米泉市| 贵定县| 太康县| 南召县| 阜平县| 万年县| 黔东| 闽侯县| 铜川市| 抚宁县| 永安市| 阳谷县| 共和县| 阳原县| 锡林郭勒盟| 江北区| 临沧市| 云南省| 百色市| 镇安县| 苍溪县| 富顺县| 柘荣县| 虹口区| 佛教| 洛川县| 汉寿县| 舞阳县| 邯郸县| 珠海市| 杨浦区| 四川省| 海城市|