4

クラスには次のロックメカニズムがあります。このプログラムを実行すると、1つのスレッドが継続的にロックを取得して再取得しますが、他のスレッドにロックを取得する機会を与えることはなく、飢餓につながります。スレッドがロックを放棄すると、別のスレッドがロックを取得するように、ロックメカニズムを再構築するにはどうすればよいですか?他のスレッドがロックを取得し、ロックされているスレッドの実行が停止するまで待つ必要がないようにしたいと思います。

  private final ReentrantLock lock = new ReentrantLock();
  private final Condition condition = lock.newCondition();

  private final Map<Integer, Long> locksMap = new HashMap<Integer, Long>();

  /** {@inheritDoc} */
  @Override
  public long lock(int recNo) throws RecordNotFoundException {
    ValidationUtils.checkNegative(recNo);

    lock.lock();
    long id = Thread.currentThread().getId();
    try {
      while (locksMap.get(recNo) != null) {
        try {
          System.out.println("Thread " + id + " is waiting.");
          condition.await();
        }
        catch (InterruptedException e) {
          LOGGER.log(Level.SEVERE, e.getMessage());
          return -1;
        }
      }
      Long prevValue = locksMap.put(recNo, id);
      if (prevValue != null) {
        String msg = "Expected no value for " + recNo + " but was ";
        msg += prevValue + ".";
        throw new IllegalStateException(msg);
      }
      System.out.println("Thread " + id + " has the lock.");
    }
    finally {
      lock.unlock();
    }
    return id;
  }

  /** {@inheritDoc} */
  @Override
  public void unlock(int recNo, long cookie) throws RecordNotFoundException, SecurityException {
    ValidationUtils.checkNegative(recNo);
    if (cookie < 0) {
      throw new IllegalArgumentException("cookie is negative.");
    }

    lock.lock();
    try {
      if (locksMap.get(recNo) == cookie) {
        locksMap.remove(recNo);
      }
      else {
        String msg = "Wrong lock cookie. Expected " + locksMap.get(recNo);
         msg += ", was " + cookie + ".";
        throw new IllegalStateException(msg);
      }
      long id = Thread.currentThread().getId();
      System.out.println("Thread " + id + " no longer has the lock.");
      condition.signalAll();
    }
    finally {
      lock.unlock();
    }
  }

  /**
   * Tests the locking mechanism in this class.
   * 
   * @param args None.
   */
  public static void main(String... args) {
    ExecutorService threadPool = Executors.newFixedThreadPool(5);
    final CountDownLatch latch = new CountDownLatch(5);
    final Data data = new Data();
    Runnable task = new Runnable() {
      @Override
      public void run() {
        try {
          for (int index = 0; index < 10; index++) {
            long cookie = data.lock(1);
            Thread.sleep(1000); // Do something.
            data.unlock(1, cookie);
          }
        }
        catch (SecurityException e) {
          e.getStackTrace();
        }
        catch (RecordNotFoundException e) {
          e.getStackTrace();
        }
        catch (InterruptedException e) {
          e.getStackTrace();
        }
        finally {
          latch.countDown();
        }
      }
    };
    for (int index = 0; index < 5; index++) {
      threadPool.execute(task);
    }
    try {
      latch.await();
    }
    catch (InterruptedException e) {
      e.getStackTrace();
    }
    threadPool.shutdown();
  }

これが出力です。スレッド9は、ループが終了した後にのみロックの取得を停止することに注意してください。

Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 9 has the lock.
Thread 13 is waiting.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 9 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 13 has the lock.
Thread 12 is waiting.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 13 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 12 has the lock.
Thread 11 is waiting.
Thread 10 is waiting.
Thread 12 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 11 has the lock.
Thread 10 is waiting.
Thread 11 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
Thread 10 has the lock.
Thread 10 no longer has the lock.
4

4 に答える 4

11

ReetrantLockFair ポリシーで使用します。公正なポリシーは、スレッドの枯渇を回避します。

private final ReentrantLock lock = new ReentrantLock(true);

Java ドキュメント

public ReentrantLock(boolean fair) 指定された公平性ポリシーで ReentrantLock のインスタンスを作成します。パラメータ: fair - このロックが公平である場合は true。そうでなければ偽

于 2012-08-18T06:57:28.853 に答える
6

私はあなたがすでに受け入れられる答えを持っていることを知っています、しかし私はちょうど私の2¢を加えたいです。

シングルコアマシンまたはデュアルコアマシンなどで実行している場合、問題は、JVMが別のスレッドにロックの機会を与えるのに十分な頻度でスレッドをスワップしていないことである可能性があります。

いずれの場合もThread.yield()、ロックを解放した後に呼び出すだけで、元のスレッドが再びロックを取得する前に、他のスレッドがロックを取得できるようになります。

于 2012-08-18T06:11:18.720 に答える
2

一般に、ロックは長時間保持されるべきではありません。そう

        long cookie = data.lock(1);
        Thread.sleep(1000); // Do something.
        data.unlock(1, cookie);

容認できません。この方法では、常に 1 つのスレッドだけが「何かを実行」します。提案どおりに yeild() または sleep() を追加しても、スループット パフォーマンスは変わりません。ロックを取得し、タスクを取得し、ロックを解放してから、「何かをする」必要があります。

于 2012-08-18T06:44:29.210 に答える
0

スレッドがロックを放棄したら、Thread.sleep(int millis)を使用して、別のスレッドがそれを取得するのに十分な時間スリープさせてみませんか?

于 2012-08-18T05:52:37.533 に答える