12

I'm writing a computational library in scala. Similar functionality I group into native scala singleton objects containing bunch of procedures and some statically allocated memory for O(1) temporal data.

This approach is suited for a single-thread use. But calling library functions from different threads simultaneously may overwrite temporal data and give incorrect answers to callers.

I may just copy this library and write thread-safe version by moving all statically allocated memory inside functions local space. But I prefer to avoid it by defining thread-local variables.

Is it possible in scala?

ayvango
  • 5,867
  • 3
  • 34
  • 73

2 Answers2

27

Just use Java's java.lang.ThreadLocal class to store the variables.

val tl = new ThreadLocal[String]
tl.set("fish")
tl.get   // "fish"

Be aware that there is a nonzero performance penalty for doing this (~6 ns in my hands, as I recall). If you're doing really lightweight stuff (e.g. incrementing an index), you might notice the difference in speed.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • 4
    Also note that there is scala's `DynamicVariable` which is basically a wrapper around `InheritableThreadLocal`. It does not provide any option for non-inheritable thread locals though. – Régis Jean-Gilles Jan 05 '13 at 22:26
  • @ Régis Jean-Gilles Maybe it's not related strictly to OP's question, but: you mentioned `InheritableThreadLocal`, seems it does not combines well with `Executors` framework because of pooling. Is there a use case for such variables, besides stuff that is keeped in deprecated `new Thread().start()` ? – idonnie Jan 06 '13 at 00:02
  • `DynamicVariable` is useful for implementing the *dynamic scope pattern*. See my other answer by example: http://stackoverflow.com/a/13252952/1632462. However it must never be used in a multi-threaded context, where it just won't work. – Régis Jean-Gilles Jan 06 '13 at 11:11
13

Since Java 8 release, there is a more declarative way to initialize ThreadLocal:

Scala:

val local = ThreadLocal.withInitial[String](() => "init value");

Analogue in Java:

ThreadLocal<String> local = ThreadLocal.withInitial(() -> "init value");

Until Java 8 release you had to do the following:

Scala:

val local = new ThreadLocal[String]{
  override def initialValue = "init value"
}

Analogue in Java:

ThreadLocal<String> local = new ThreadLocal<String>(){
    @Override
    protected String initialValue() {
        return "init value";
    }
};

Note: Evaluation is lazy since you are passing java.util.function.Supplier lambda that is evaluated only once when ThreadLocal#get is called but value was not previously evaluated.

Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96