まず、学習シラバス
- キュー、分類、基本的な方法を定義します
- キューの実装コード
- 基礎となるキュー(配列、リンクリスト)
- 分類キュー:キュー、循環キュー
第二に、キュー
- 定義されたキュー一高度、第アウトリストデータ構造線形制約の操作含まれ、エンキューをエンキュー()およびデキュー()二つの基本的な操作。
非常に基本的なデータ構造としては、アプリケーションキューは、非常に広いまた、キュー、同時キューをブロック循環キューなどの特定の追加機能、と特にいくつかのキューです。彼らは部分的に基礎となるシステム、フレーム、ミドルウェアの多くは、重要な役割を果たして開発しています。例えば、高性能キューかく乱、Linuxのリングバッファは、サイクル同時キューを使用していた。Javaの同時使用ArrayBlockingQueueとの契約は、公正なロックを達成するために、など
- キュー(配列)を達成するJava
// 用数组实现的队列
public class ArrayQueue {
// 数组:items,数组大小:n
private String[] items;
private int n = 0;
// head表示队头下标,tail表示队尾下标
private int head = 0;
private int tail = 0;
// 申请一个大小为capacity的数组
public ArrayQueue(int capacity) {
items = new String[capacity];
n = capacity;
}
// 入队
public boolean enqueue(String item) {
// 如果tail == n 表示队列已经满了
if (tail == n) return false;
items[tail] = item;
++tail;
return true;
}
// 出队
public String dequeue() {
// 如果head == tail 表示队列为空
if (head == tail) return null;
// 为了让其他语言的同学看的更加明确,把--操作放到单独一行来写了
String ret = items[head];
++head;
return ret;
}
}
基本的なコード上記キューを満たす:アプリケーションは、一般的に、配列の大部分はヘッドは、より少ないテールポインタよりもできなくても、アドレスの後に充填されたときに、不足している記憶空間、エンキュー判定条件、デキュー条件判定に関しその後、チームに、そしてあなたが必要とする今回のデータ移動は、すべてのチームが操作を持つ新しい要素を挿入ではなく、後に、私たちはデータを移動する必要がある場合、キューの中の私たち単に空き領域のない、それが焦点に必要となった原因変換するエンキュー()関数のチームのニーズに、この時間を移動操作:
// 入队操作,将item放入队尾
public boolean enqueue(String item) {
// tail == n表示队列末尾没有空间了
if (tail == n) {
// tail ==n && head==0,表示整个队列都占满了
if (head == 0) return false;
// 数据搬移
for (int i = head; i < tail; ++i) {
items[i-head] = items[i];
}
// 搬移完之后重新更新head和tail
tail -= head;
head = 0;
}
items[tail] = item;
++tail;
return true;
}
イラスト:
- ベースのリストキューの実装方法
- ヘッドポインタとテールポインタ。彼らは、最初のノードと最後のリンクリストのノードを指します。示されているように、ときチーム、tail->次= new_node、尾= tail->次回、時間デキュー、ヘッド=頭部>次。
- 循環キュー
- アレイベースの実装され、時にテール= n個のデータを移行する必要がある場合、損失がパフォーマンスが落ちる、それを回避するための方法はありませんか?これは、円形のキューです。
- 图中这个队列的大小为 8,当前 head=4,tail=7。当有一个新的元素 a 入队时,我们放入下标为 7 的位置。但这个时候,我们并不把 tail 更新为 8,而是将其在环中后移一位,到下标为 0 的位置。当再有一个元素 b 入队时,我们将 b 放入下标为 0 的位置,然后 tail 加 1 更新为 1。
完成循环队列的代码,最关键的是:确定好队空和队满的判定条件,队满的判断条件是 tail == n,队空的判断条件是 head == tail;
就像我图中画的队满的情况,tail=3,head=4,n=8,所以总结一下规律就是:(3+1)%8=4。多画几张队满的图,你就会发现,当队满时,(tail+1)%n=head;
public class CircularQueue {
// 数组:items,数组大小:n
private String[] items;
private int n = 0;
// head表示队头下标,tail表示队尾下标
private int head = 0;
private int tail = 0;
// 申请一个大小为capacity的数组
public CircularQueue(int capacity) {
items = new String[capacity];
n = capacity;
}
// 入队
public boolean enqueue(String item) {
// 队列满了
if ((tail + 1) % n == head) return false;
items[tail] = item;
tail = (tail + 1) % n;
return true;
}
// 出队
public String dequeue() {
// 如果head == tail 表示队列为空
if (head == tail) return null;
String ret = items[head];
head = (head + 1) % n;
return ret;
}
}
- 阻塞队列与并发队列
阻塞队列其实就是在队列基础上增加了阻塞操作。简单来说,就是在队列为空的时候,从队头取数据会被阻塞。因为此时还没有数据可取,直到队列中有了数据才能返回;如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后再返回。
阻塞队列存在并发的问题:
线程安全的队列我们叫作并发队列。最简单直接的实现方式是直接在 enqueue()、dequeue() 方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或者取操作。实际上,基于数组的循环队列,利用 CAS 原子操作,可以实现非常高效的并发队列。这也是循环队列比链式队列应用更加广泛的原因。在实战篇讲 Disruptor 的时候,我会再详细讲并发队列的应用。
三、引入问题:线程池没有空闲线程时,新的任务请求线程资源时,线程池该如何处理?各种处理策略又是如何实现的呢?
- 我们一般有两种处理策略。第一种是非阻塞的处理方式,直接拒绝任务请求;另一种是阻塞的处理方式,将请求排队,等到有空闲线程时,取出排队的请求继续处理。那如何存储排队的请求呢?
- このキュー・データ構造がキューに入れられた要求を格納するのに非常に適しているように、我々は、最初のサーブ、高度、各キューの要求の公平な扱いをしたいです。我々が言ったように、これらの2つの実装に基づいて、リンクされたリストや配列に基づいてキューがあります。キューに入れられた要求のための両方の実装は、それがどのような違いを生むのでしょうか?
- リンクリストのベースの実装では、あなたは、アンバウンド形式のキュー(アンバウンド形式のキュー)のサポート無制限のラインを実現することができますが、長すぎる、あまりにも多くの要求がキューイングされている要求応答処理時間を生じ得ます。だから、無限のキュースレッドプールリンクリストの実装に基づいて、システムのより敏感な応答時間のために適切ではありません。
- 有界(有界キュー)上のキュー、キューを達成するために、配列の有限のサイズ、スレッドプールが要求をキューに入れられたが、キューのサイズを超えて、次の要求は、このような応答時間に敏感なシステムでは、拒否されます、比較的より合理的。しかし、キューサイズの合理的なセットは、非常に豪華です。キューは、あまりにも多くの保留中の要求に大きすぎると、キューが小さすぎると、システムリソース、最大化の性能をフルに活用をしないためにつながります。
- キュー外スレッドプールシーンキューに入れられた前述のアプリケーション・キュー・リクエストに加えて、そのようなデータベース接続プールなど、要求をキューイングするための任意の限られたリソースプールに適用することができます。空きリソースがない場合に実際には、ほとんどの限られた資源のシナリオのために、要求キュー「キュー」は、このデータ構造によって、基本的に実装することができます。
第四に、放課後の思考
- このプールの構造は、要求をキューイングに使用されるスレッドプールに加えて、あなたはまた、同様のセル構造やシーンはキューがそれを要求キューイングに使用されるかを知っていますか?
- 今日はロックフリー同時キューを達成するためにどのように同時キューについて話しました、オンラインディスカッションがたくさんあります。この問題では、どのようにそれを見ていますか?