I'm relatively new to Scala and functional programming, and I like the idea that using immutable objects I can avoid many thread safety pitfalls. One thing still haunts me, and it's the classical example used to teach thread safety - the shared counter.
I was wondering if it would be possible to implement a thread-safe counter (a request counter in this example), using immutable objects, and functional concepts, and avoid synchronization completely.
So for reference here are first the classical mutable versions of the counter (excuse me for the public member variable, just for brevity of the examples)
Mutable, Non thread safe 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 thread safe version: (or so I hope...)
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);
}
}
I was wondering if there is a way using immutable objects, and volatile variables to achieve thread safety without synchronization.
So here was my naive attempt. The idea is to have an immutable object for the counter, and just replace the reference to it, using a volatile variable. Feels fishy, but worth a shot.
Holder:
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;
}
}
Modified 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);
}
}
I have a strong feeling this is also not thread safe, as I'm reading from incrementer, and might get a stale value (e.g. if the reference was already replaced by another thread). In case it's indeed not thread safe, then I wonder if there is at all any "functional" way to handle such a counter scenario without locking / synchronization.
So my question(s) are
- Is this thread safe by any chance?
- If yes, why?
- If not, is there at all any way to implement such a counter without synchronizing?
Although the example code above is in Java, replies in Scala are of course also welcome