2

Java Stringクラスは不変でスレッドセーフであることを読みましたが、Stringsの参照割り当てがスレッドセーフであるかどうかについてはまだ混乱しています。

最初の質問:Foo.setString()スレッドBが呼び出している間にスレッドAが呼び出した場合Foo.getString()、次のコードはスレッドセーフですか?

Class Foo {
    String aString;
    public String getString() {
        return aString;
    }
    public void setString(s) {
        aString = s;
    }
}

2番目の質問: ReentrantLockを使用して、上記のコードがスレッドセーフでない場合、Foo.getString()メソッドを作成するにはどうすればよいですか?

Class Foo {
    String aString;
    ReentrantLock aLock;
    public String getString() {
        aLock.lock();
        return aString;
        aLock.unlock(); // This line will be unreachable. How to fix??
    }
    public void setString(s) {
        aLock.lock();
        aString = s;
        aLock.unlock();
    }
}

tryLock(timeout)機能を使用する必要があるため、ReentrantLockを使用する必要があります。

4

3 に答える 3

2

質問1:スレッドセーフの意味によって異なりますが、Eric Lippertはここに非常に優れたブログ投稿を書いています...しかし、aStringを揮発性として宣言すると、異なるスレッドでの読み取りが正しいことが保証されます。

質問2:

try ... finallyを使用して、finallyブロックでロックを解除します。例:

public String getString() {
  try {        
    aLock.lock();
    return aString;
  } finally {
    aLock.unlock();
  }
}

public void setString(s) {
  try {        
    aLock.lock();
    aString = s;
  } finally {
    aLock.unlock();
  }
}
于 2011-11-13T18:00:21.060 に答える
2

この場合、必要なのは揮発aString性にすることだけです(つまり、書き込み後の読み取りでは常に最新の値が表示されます)-メソッドを同期させることは、単一のステートメントのみを実行しているため、特に有用ではありません-どちらの場合も、より多くの作業を行いたい場合は、とにかくより高いレベルの同期が必要です(「文字列がXYZの場合は、XYAを割り当てます」と言います)。つまり、同期と揮発性の両方で同じ保証が得られます(クラスの他の場所で同期を使用する場合の明らかな違いは別として)

したがって、volatileは十分でパフォーマンスが高くなりますが、同期は同じように問題ありません。パフォーマンスの違いに気付くのは、競合するアクセスが多数ある場合だけですが、それ以外の場合は問題ありません。同期は、少なくとも競合しないアクセスに対して非常に最適化されています。ホットスポット(ただし、最近のすべてのJVMにも同じことが当てはまると思います)。

于 2011-11-13T18:11:48.877 に答える
1

同期キーワード を使用:

   public synchronized String getString() {
        return aString;
    }

    public synchronized void setString(s) {
        aString = s;
    }
于 2011-11-13T18:00:22.340 に答える