LinkedBlockingQueue も一方向リンク リストを使用して実装されています。また、最初と最後のノードをそれぞれ格納するために使用される 2 つのノードがあり、初期値 0 のアトミック変数 count もあります。キュー要素の数を記録するために使用されます。また、ReentrantLock のインスタンスが 2 つあり、それぞれ要素の入力とキューからの要素のアトミック性を制御するために使用されます。このうち、takeLock は、1 つのスレッドだけが同時にキュー ヘッドから要素を取得でき、他のスレッドは取得する必要があることを制御するために使用されます。 PutLock は、同時に 1 つのスレッドだけがキュー ヘッドから要素を取得できるように制御します。1 つのスレッドがロックを取得して要素をキューの最後に追加でき、他のスレッドは待機する必要があります。さらに、notEmpty と notFull は条件変数であり、キューに出入りするときにブロックされるスレッドを格納するための内部条件キューがあります。実際、これはプロデューサー/コンシューマー モデルです。以下は排他ロックを作成するコードです。
private final AtomicInteger count = new AtomicInteger(); /** Lock held by take, poll, etc */ private final ReentrantLock takeLock = new ReentrantLock(); /** Wait queue for waiting takes */ private final Condition notEmpty = takeLock.newCondition(); /** Lock held by put, offer, etc */ private final ReentrantLock putLock = new ReentrantLock(); /** Wait queue for waiting puts */ private final Condition notFull = putLock.newCondition();
呼び出し元のスレッドが LinkedBlockingQueue インスタンス上でテイクやポーリングなどの操作を実行するときは、1 つのスレッドだけがリンクされたインスタンスのヘッド ノードを操作できるようにするために、takeLock ロックを取得する必要があります。同時にリストアップします。さらに、条件変数 notEmpty 内の条件キューの維持には takeLock のロック状態管理メカニズムが使用されるため、呼び出しスレッドは notEmpty の await メソッドと signal メソッドを呼び出す前に、まず takeLock ロックを取得する必要があります。そうしないと、IllegalMonitorStateException 例外がスローされます。 。 NotEmpty は内部的に条件キューを保持しており、スレッドが takeLock を取得して notEmpty の await メソッドを呼び出すと、呼び出しスレッドはブロックされ、スレッドは notEmpty 内の条件キューに置かれ、スレッドが notEmpty を呼び出すまで待機します。方法。
LinkedBlockingQueue インスタンスで put や Offer などの操作を実行するときは、putLock ロックを取得して、1 つのスレッドだけがリンク リストの末尾ノードを同時に操作できるようにする必要があります。時間。同様に、条件変数 notFull 内の条件キューの維持には putLock のロック状態管理メカニズムが使用されるため、呼び出しスレッドは notFull の await メソッドと signal メソッドを呼び出す前に、まず putLock ロックを取得する必要があります。そうしないと、IllegalMonitorStateException 例外がスローされます。 NotFull は内部的に条件キューを保持します。スレッドが putLock ロックを取得して notFull の await メソッドを呼び出すと、呼び出しスレッドはブロックされ、スレッドは notFull 内の条件キューに置かれ、スレッドが notFull を呼び出すまで待機します。信号方式。以下は、LinkedBlockingQueue のパラメーターなしのコンストラクターのコードです。
次は LinkedBlockingQueue のパラメーターなしの構築コードです
public static final int MAX_VALUE = 0x7fffffff; public LinkedBlockingQueue() { this(Integer.MAX_VALUE); } public LinkedBlockingQueue(int capacity) { if (capacity <= 0) throw new IllegalAgrumentException(); this.capacity = capacity; last = head = new Node<E>(null); }
このコードから、デフォルトのキュー容量が 0x7fffffff であることがわかり、ユーザーは指定することもできます容量自体が大きいため、ある程度、LinkedBlockingQueue は制限されたブロッキング キューであると言えます。
オファー操作
public boolean offer(E e) { //(1) if (e == null) throw new NullPointerException(); //(2) final AtomicInteger count = this.count; if (count.get() == capacity) return false; //(3) int c = -1; Node<E> node = new Node<E>(e); final ReentrantLock putLock = this.putLock; putLock.lock(); try { //(4) if (count.get() < capacity) { enqueue(node); c = count.getAndIncrement(); //(5) if (c + 1 < capacity) notFull.signal(); } } finally { //(6) putLock.unlock(); } //(7) if (c == 0) signalNotEmpty(); //(8) return c >= 0; }
コード (2) は、現在のキューがいっぱいかどうかを判断し、現在の要素を破棄して false を返します
コード (3) putLock ロックを取得すると、現在のスレッドがロックを取得した後、プットおよびオファー操作を呼び出す他のスレッドがブロックされます (ブロックされたスレッドは putLock ロックの AQS ブロッキング キューに配置されます)。
コード (4) は、現在のキューが満杯であるかどうかを再判断します。これは、コード (2) の実行およびオブジェクトの取得中に、他のスレッドが put または Offer 操作を通じてキューに新しい要素を追加した可能性があるためです。 putLock ロック。キューが実際にいっぱいではない場合、新しい要素がキューに追加され、カウンターが増分されます。
コード (5) は、新しい要素がキューに追加された後もキューに空き領域がある場合、notFull の await 操作が呼び出されるために notFull 条件付きキューが起動することを判断します (次のような場合)。 put メソッドが実行され、キューがいっぱいになります) キューが空になっているため、ブロックされたスレッドはキューに入れられたスレッドを事前にウェイクアップできます。
コード(6)は取得したputLockロックを解放しますが、tryブロックが例外をスローしてもfinallyが実行されるため、ロックの解放はfinallyで行う必要があることに注意してください。さらに、ロックが解放された後、put 操作の呼び出しによりブロックされた他のスレッドの 1 つがロックを取得します。コード (7) の
C0 は、コード (6) を実行してロックを解放するときに、キューに少なくとも 1 つの要素があることを示します。キューに要素がある場合、signalNotEmpty 操作が実行されます。 ##
以上がJava 同時プログラミングで LinkedBlockingQueue キューを使用する方法は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。