1

セマフォのカウントの仕組みを理解するために、単純なバージョンを実装することにしました。現在の実装が実際に正しい実装であることを確認したかったのですが、明らかなことは何も見逃していません

public class CountingSemaphore {
    private int limit;

    public CountingSemaphore(int limit) {
        this.limit = limit;
    }

    public synchronized void acquire() {
        try {
            if (limit == 0)
                wait();

            limit--;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public synchronized void release() {
        try {
            if(limit == 0) 
                notifyAll();

            limit++;
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

}
4

4 に答える 4

3

これは、1 つの詳細を除いて機能するはずです。
を使用notifyAll()しているため (そして @JBNizet が指摘しているように、偽のウェイクアップのリスクがあるため)、いくつかの待機中のスレッドをウェイクアップできます。これらはすべて解放され、減少しlimitます。
変化する

if (limit == 0)
    wait();

while (limit == 0) {
    wait();
}

そしてあなたは大丈夫なはずです。

于 2012-09-24T19:41:19.253 に答える
3

wait()スプリアス ウェイクアップが発生するため、ウェイクアップ条件をチェックする while ループ内に常に含める必要があります。詳細については、javadocを参照してください。

例外をキャッチして飲み込むことは、非常に悪い習慣です。メソッドはInterruptedExceptionacquire()をスローする必要があります。release メソッドは Exception をキャッチすべきではありません。

また、セマフォ自体をロックとして使用することはありません。外部クラスがセマフォを使用して、まったく関係のないものを同期する可能性があり、パフォーマンスの低下やデッドロックにつながる可能性があります。プライベート最終ロック オブジェクトを使用します。

于 2012-09-24T19:41:38.390 に答える
0

クライアントの観点からは、値 >= 0 でセマフォを使用するように強制する必要があります。

于 2012-09-24T19:42:42.713 に答える
0

コードに問題があります。 release を呼び出すと、notify all but here を呼び出します

public synchronized void acquire() {
        try {
            if (limit == 0)
                wait();

            limit--;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

待機しているすべてのスレッドが解放され、git limit<0 を実行できます。ここでの一般的な解決策は、ループを使用することです。

 while(limit == 0){
     wait();
}
于 2012-09-24T19:42:47.527 に答える