0

私のアプリケーションでは、次の 2 つのことが起こります。

  • さまざまなスレッドがジョブを生成します。
  • ジョブを消費する関数があります (ただし、常に実行されているスレッドは 1 つではありません)。この関数はプロデューサーによって開始されますが、一度だけ実行されるようにロックされています。

たとえば、ジョブが生成されます。

addJobToDatabase(...);
triggerPass();

そして、これがコンシューマ関数の開始方法です:

public void triggerPass() {

    // prevent running more than once
    if (onceLock.tryLock()) { // onceLock is a ReentrantLock
        try {

            while (haveJobs()) {
                doJobs();
            }

        } finally {
            onceLock.unlock();
        }
    } else {
        log.info("Pass triggered, but already running");
    }

}

ここで、小さな競合状態が発生する可能性があります。もしも

  • スレッド A は を離れましたwhileが、まだ完了していませんonceLock.unlock()
  • スレッド B はonceLock.tryLock()false を返します

...スレッド B のジョブは、後で triggerPass() を呼び出すまで実行されません。

実際に問題が発生するとは思えませんが、この小さなギャップを正確に埋めることができますか?

4

2 に答える 2

0

tryLock()に置き換えることで回避できたと思いますtryLock(1, TimeUnit.SECONDS)。しかし、それは良くありませんし、との間の遅延there are no more jobsunlock()1秒より長い場合(そしてデータベースで何が起こっているかを誰が知っているか)、絶対確実ではありません。

于 2012-12-10T13:48:06.410 に答える
0

残念ながら、この設計では競合状態は避けられません。正しくしたいですか?読み取り-変更-書き込みアクションが単一のアトミック操作であるイテレーターやキューのようなものを作成してみませんか?

public void triggerPass() {
    Job job = null; 
    while ((job = jobIterator.next()) != null) {
        doJob(job);
    }
}
于 2012-12-10T16:19:32.737 に答える