1

run method以下は、 で、常に取得しようとしunique id from the availableExistingIdsているコードであり、releasingを作成することによって同時に取得しようとしていますlinked list orderが、特定のケースでは、取得していてNoSuchElementException、id はzero few timesいつでもそうであってはならないと思います。

class IdPool {
    private final LinkedList<Integer> availableExistingIds = new LinkedList<Integer>();

    public IdPool() {
        for (int i = 1; i <= 1000; i++) {
            availableExistingIds.add(i);
        }
    }

    public synchronized Integer getExistingId() {
        return availableExistingIds.removeFirst();
    }

    public synchronized void releaseExistingId(Integer id) {
        availableExistingIds.add(id);
    }
}


class ThreadNewTask implements Runnable {
    private IdPool idPool;
    private int id;

    public ThreadNewTask(IdPool idPool) {
        this.idPool = idPool;
    }

    public void run() {
        try {
            id = idPool.getExistingId();
            //Anything wrong here?  
                    if(id==0) {
                        System.out.println("Found Zero");
                    }
            someMethod(id);
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            idPool.releaseExistingId(id);
        }
    }

    // This method needs to be synchronized or not?
            private synchronized void someMethod(Integer id) {
                System.out.println("Task: " +id);
                // and do other calcuations whatever you need to do in your program
            }
}

問題文:-

zero id caseここのコードでこれを回避するにはどうすればよいですか? id = 0 を取得できるシナリオの 1 つは、id プールが使い果たされた (空になった) 場合です。その場合、次の行:

id = idPool.getExistingId();

で失敗しNoSuchElementExceptionます。この場合、finally ブロックが実行されます。

idPool.releaseExistingId(id);

default value of 0ただし、最初の行が失敗したため、id はまだ保持されます。0したがって、最初はプールになかったにもかかわらず、「解放」してIDプールに追加し直すことになります。その後、後のタスクは合法的に 0 を取ることができます。そして、それは私が必要としないものです。私のコードでこのシナリオを克服する方法を誰かに提案できますか? 私は常に id が の範囲内にあることを望んでいます1 to 1000

4

1 に答える 1

5

使用可能な ID がない場合にクラッシュするのではなく、ID が使用可能になるのを待つようにコードを変更してみませんか?

そうしないと、一度に多くのスレッドを処理するたびにプールが使い果たされ、多くの失敗したスレッドに対処しなければならなくなります。また、同期作業は自動的に処理されます。

編集:ここに変更されたコードがあります

class ThreadNewTask implements Runnable {
  private BlockingQueue<Integer> pool;
  private int id;

  public ThreadNewTask(BlockingQueue<Integer> pool) {
    this.pool = pool;
  }

  public void run() {
    try {
        id = pool.take();
        someMethod(id);
    } catch (Exception e) {
        System.out.println(e);
    } finally {
        pool.offer(id);
    }
  }

  private void someMethod(Integer id) {
    System.out.println("Task: " +id);
            // and do other calcuations whatever you need to do in your program
  }
}  

次に、次のような方法でプールを初期化します。

LinkedList<Integer> availableExistingIds = new LinkedList<Integer>();
for (int i = 1; i <= 1000; i++) {
  availableExistingIds.add(i);
}
BlockingQueue<Integer> pool = new ArrayBlockingQueue<Integer>(1000, false, availableExistingIds);
于 2012-08-18T18:00:10.087 に答える