私はScalaと関数型プログラミングには比較的新しいので、不変なオブジェクトを使うとスレッドセーフの落とし穴を避けることができます。 1つのことはまだ私を悩ましています。スレッドセーフティを教えるために使用される古典的な例 - 共有カウンタです。スレッドセーフな共有カウンタを実装するための機能的方法
スレッドセーフカウンタ(この例ではリクエストカウンタ)を実装し、不変なオブジェクトと機能概念を使用して同期を完全に回避できるかどうかは疑問でした。
:ここに参照のためにそうは、第1のカウンタ の古典可変バージョン(ちょうど例の簡略化のために、パブリックメンバ変数のためにすみません)
変更可能な、非スレッドセーフ版です
public class Servlet extends HttpServlet { public int requestCount = 0; @Override public void service(ServletRequest req, ServletResponse res) throws ... { requestCount++; //thread unsafe super.service(req, res); } }
変更可能な、クラシック、スレッドセーフ版:(またはので、私は願っています...)
public class Servlet extends HttpServlet {
public volatile int requestCount = 0;
@Override
public void service(ServletRequest req, ServletResponse res) throws ... {
synchronized (this) {
requestCount++;
}
super.service(req, res);
}
}
不変なオブジェクトと揮発性変数を使用する方法がある場合は、同期なしでスレッドの安全性を実現する方法があるのだろうかと思っていました。
ここで私の素朴な試みでした。この考え方は、カウンタに不変なオブジェクトを持たせ、揮発性の変数を使ってその参照を置き換えるだけです。怪しげな気分だが、一発の価値がある。
ホルダー:
public class Incrementer {
private final int value;
public Incrementer(final int oldValue) {
this.value = oldValue + 1;
}
public Incrementer() {
this.value = 0;
}
public int getValue() {
return value;
}
}
修正サーブレット:
public class Servlet extends HttpServlet {
public volatile Incrementer incrementer = new Incrementer();
@Override
public void service(ServletRequest req, ServletResponse res) throws ... {
incrementer = new Incrementer(incrementer.getValue());
super.service(req, res);
}
}
私はこれは私がインクリメンタから読んでいるとしても、スレッドセーフされていない、となるかもしれない強い気持ちを持っています古い値(例えば、参照がすでに別のスレッドに置き換えられている場合など)。実際にスレッドセーフではない場合は、ロック/同期なしにこのような対抗シナリオを処理するための「機能的」な方法はまったくないのだろうかと思います。
だから私の質問(複数可)
- は、このスレッドは、万が一安全ですか?
- 「はい」の場合、なぜですか?
- そうでなければ、同期させずにそのようなカウンタを実装する方法はありますか?
上記の例のコードは、Javaでですがが、Scalaで返信もちろん
興味深いことに、AtomicIntegerは内部的に同期を使用しているので、私はそれを答えとして考えていませんでしたが、目標を達成するためにいくつかの他の方法(ネイティブコード)を使っているようです。 /grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java –