JAvaスレッド信号量の簡単な例

1694 ワード

通常、複数のスレッドが少ないリソースにアクセスする必要がある場合があります.サーバ上でクライアント要求に答えるスレッドがいくつか実行されていると想定する.これらのスレッドは同じデータベースに接続する必要がありますが、いずれの時点でも一定数のデータベース接続しか取得できません.これらの固定数のデータベース接続を大量のスレッドに効率的に割り当てるにはどうすればいいですか?1つのリソースのセットへのアクセスを制御する方法(単純にロックされる以外)は、周知の信号量カウント(counting semaphore)を使用することである.信号量カウントは、取得可能なリソースのセットの管理をカプセル化する.信号量は,単純なロックに基づいて実現され,スレッドを安全に実行し,利用可能なリソース個数に初期化できるカウンタに相当する.例えば、信号量を取得可能なデータベース接続数に初期化することができます.あるスレッドが信号量を取得すると、取得可能なデータベース接続数が1つ減少します.スレッドがリソースを消費して解放すると、カウンタが1つ追加されます.信号量制御のすべてのリソースが占有されている場合、スレッドがこの信号量にアクセスしようとすると、利用可能なリソースが解放されるまでブロック状態になります.
信号量の最も一般的な使い方は「消費者-生産者の問題」を解決することである.1つのスレッドが動作する場合、別のスレッドが共有変数にアクセスすると、この問題が発生する可能性があります.消費者スレッドは、生産者スレッドが生産を完了してからのみデータにアクセスできます.この問題を解決するために信号量を使用するには、消費者スレッドがこの信号量にアクセスするときにブロックされるように、ゼロに初期化された信号量を作成する必要がある.職場の仕事が終わるたびに、生産者スレッドはその信号量に信号を送信します(リソースを解放する).消費者スレッドが単位生産結果を消費し、新しいデータユニットを必要とするたびに、信号量を再び取得しようとする.そのため、信号量の値は常に生産済みで消費可能なデータユニット数に等しい.この方法は、消費者スレッドを用いて利用可能なデータユニットがあるかどうかをチェックする方法よりもずっと効率的である.消費者スレッドが目を覚ますからである.来ると、利用可能なデータユニットが見つからないと、再びスリープ状態になり、このようなオペレーティングシステムのオーバーヘッドは非常に高価になります.
信号量はJava言語で直接サポートされていないが,オブジェクトに鍵をかけた上で容易に実現できる.簡単な実装方法を以下に示します.
class Semaphore {
   private int count;
   public Semaphore(int n) {
      this.count = n;
   }
   public synchronized void acquire() {
      while(count == 0) {
         try {
            wait();
         } catch (InterruptedException e) {
            //keep trying
         }
      }
      count--;
   }
    
   public synchronized void release() {
      count++;
      notify(); //alert a thread that's blocking on this semaphore
   }
}