3

(ロック オブジェクトを使用する代わりに) プライベート フィールド変数をロックすることは安全で許容可能な方法ですか? このようにして、さまざまな目的のためにさまざまなロックを設定できます。以下の例:

class Test {
  private Integer x = 0;
  private Integer y = 0;

  public void incrementX() {
    synchronized(x) {
      x++;
    }
  }

  public void decrementX() {
    synchronized(x) {
      x++;
    }
  }

  public void incrementY() {
    synchronized(y) {
      y++;
    }
  }

  public void decrementY() {
    synchronized(y) {
      y++;
    }
  }

または、ロックしたいプライベート メンバーごとにロック オブジェクトを用意する必要がありますか? 例:

class Test {
  private final Object xLock = new Object();
  private final Object yLock = new Object();
  private Integer x = 0;
  private Integer y = 0;

...

}

それとも、一般的なロックを 1 つだけ用意し、それをロックが必要なすべてのプライベート変数に使用する必要がありますか? 例:

class Test {
  private final Object objLock = new Object();
  private Integer x = 0;
  private Integer y = 0;

...

}
4

4 に答える 4

7

ロックには常に final メンバー変数を使用するように注意してください。たとえば、を使用してIntegerいて、それを変更する予定がある場合、呼び出しごとに異なるオブジェクトが表示され、データ競合が発生するため、これは非常に悪い習慣になります。

1 つまたは複数のロックを使用するかどうかは、達成したい調整スキームに依存するため、完全にドメイン固有です。どの操作が相互に排他的で、どの操作が相互に排他的でないかを慎重に検討し、適切にロックを割り当てる必要があります。ここには、単一のベスト プラクティスはありません。

データ競合を引き起こすことなく同時に発生する可能性のあるオブジェクトに対して 2 つの直交する操作がある場合、それは 2 つのロックのケースです。あなたの例では、それぞれが独立して変化する2つの整数があります。これは 2 つのロックの場合だと思います。少なくとも 1 つの操作で両方の整数にアクセスする必要がある、より複雑なコードがある場合は、それらを結び付けて、単一のロックが必要になります。

于 2012-05-11T08:37:27.090 に答える
6

このフィールドがオブジェクトである限り、private フィールドをロックすることはまったく問題ありません。プリミティブには固有のロックがないため、最初のスニペットは無効です。

ただし、このフィールドが外部からアクセスできる場合 (たとえば、ゲッターを使用) にプライベート フィールドをロックすることは避けます。したがって、2番目のソリューションは最もクリーンなIMHOです。

単一のロックを使用すると、同時に実行できるメソッドへの同時アクセスが妨げられるため、非生産的です。したがって、一般的には、ロックをきめ細かくした方がよいでしょう。

編集:

質問を変更してラッパー オブジェクトを使用したので、メソッド内でこれらの変数の値を変更するため、プライベート Integer インスタンスのロックは実際には良い解決策ではありません。最終フィールドをロックとして使用します

x++が Integer インスタンスの場合x、次と同等であることを思い出してください。

int temp = x.intValue();
temp++;
x = Integer.valueOf(temp);

さらに、Integer.valueOf() は Integer インスタンスをキャッシュするため、まったく異なるものをロックするために同じ Integer インスタンスを使用する複数のクラスが存在する可能性があります。遅い実行とデッドロックのレシピ。

于 2012-05-11T08:38:22.317 に答える
0

私の知る限り、使用するロックオブジェクトはIDとしてのみです。つまり、好きなオブジェクトを使用できます。唯一重要なことは、「2 つのものが相互に排他的でなければならない場合、それらは同じロックを使用する必要がある」ということです。

したがって、独自の変数を使用するアプローチは問題ないようです。

でも覚えておいて!!

  • プリミティブをロックできるとは思いません。Object
  • フィールド値を変更すると、次のプロセスで別のロックが取得されます!!!

したがって、セパレートロックの方が安全なようです。ただし、フィールドが変更されないことを絶対に確信している場合を除きます (実際には、 として宣言する必要がありますfinal)。

于 2012-05-11T09:39:38.423 に答える
0

2 つのフィールドに対して 2 つの異なるロックが必要だと思います。オブジェクトをロックして、2 つ以上のスレッドが同じオブジェクトに同時にアクセスするのを防ぎます。

また、Java http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.htmlの Lock オブジェクトを確認することもできます 。同期よりもパフォーマンスが高いです。 、および java.util.concurrent には、ロックを操作するためのユーティリティ クラスがいくつかあります (必要に応じて ReadWriteLock も使用します)。

于 2012-05-11T08:41:00.330 に答える