zu implementieren Ich bin relativ neu in Scala und funktionale Programmierung, und ich mag die Idee, dass mit unveränderlichen Objekten kann ich viele Thread Sicherheit Fallstricke vermeiden. Eine Sache verfolgt mich immer noch, und es ist das klassische Beispiel, das verwendet wird, um Thread-Sicherheit - den geteilten Zähler zu unterrichten.Funktionelle Möglichkeit, einen Thread Safe Shared Counter
Ich frage mich, ob es möglich wäre, einen threadsicheren Zähler (ein Anforderungszähler in diesem Beispiel) zu implementieren, unveränderliche Objekte und funktionale Konzepte zu verwenden und Synchronisierung vollständig zu vermeiden.
So Referenz hier sind zunächst die klassischen wandelbaren Versionen des Zählers (entschuldigen Sie mich für die öffentliche Membervariable, nur aus Gründen der Kürze der Beispiele)
Mutable, Nicht Thread sichere Version:
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);
}
}
Mutable Classic Faden sichere Version: (so hoffe ich ...)
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);
}
}
Ich frage mich, ob es eine Möglichkeit gibt, unveränderliche Objekte und flüchtige Variablen zu verwenden, um Thread-Sicherheit ohne Synchronisation zu erreichen.
Also hier war mein naive Versuch. Die Idee ist, ein unveränderliches Objekt für den Zähler zu haben, und einfach den Verweis darauf zu ersetzen, indem eine flüchtige Variable verwendet wird. Fühlt sich fischig an, aber einen Versuch wert.
Halter:
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;
}
}
Modifiziertes Servlet:
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);
}
}
Ich habe ein starkes Gefühl, das ist auch nicht Thread-sicher, wie ich aus Inkrementierer bin zu lesen, und vielleicht bekommen ein veralteter Wert (z. B. wenn die Referenz bereits durch einen anderen Thread ersetzt wurde). Falls es in der Tat nicht Thread-sicher ist, dann frage ich mich, ob es überhaupt einen "funktionalen" Weg gibt, ein solches Counter-Szenario ohne Locking/Synchronisation zu handhaben.
Also meine Frage (n) sind
- Ist das Gewinde durch Zufall sicher?
- Wenn ja, warum?
- Wenn nicht, gibt es überhaupt eine Möglichkeit, einen solchen Zähler ohne Synchronisierung zu implementieren?
Obwohl der Beispielcode oben in Java ist, antwortet in Scala sind natürlich auch
Interessant, ich war sicher AtomicInteger verwendet Synchronisation intern, so dass ich es nicht einmal als eine Antwort betrachtete, aber mit Blick auf den Quellcode scheint es, dass es andere Wege (nativen Code) verwendet, um das Ziel zu erreichen: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java –