Scala DynamicVariable 对 ThreadLocal 的替代

Scala DynamicVariable's replacement of ThreadLocal

我不明白DynamicVariable背后的代码和逻辑:

例如ThreadLocal 有一个有意义的经典案例 SimpleDateFormat 每次创建都非常昂贵并且不是线程安全的:

import java.text.SimpleDateFormat;

static ThreadLocal<SimpleDateFormat> dateFormatTl = new ThreadLocal<SimpleDateFormat>();
...
// many threads execute this, check if there already exists a 
// Thread-bound instance otherwise create a new one per-thread
if (dateFormatTl.get() == null) {
  dateFormatTl.set(new SimpleDateFormat("yyyy-dd-MM HH:mm:ss"));
}
// safely use the Thread-bound instance
SimpleDateFormat dateFormat = dateFormatTl.get();
dateFormat.format(new Date(java.util.Date.getTime()));

如何在 Scala 中使用 DynamicVariable 复制上述相同的功能?

// create with default instance ... 
// what for? I don't want the same instance shared across all Threads!
val dateFormatDv = new DynamicVariable[SimpleDateFormat](new SimpleDateFormat("yyyy-dd-MM HH:mm:ss"))

// many threads execute this ... 
// I see it is creating one new instance each time, and 
// that is not what I want
 dateFormatDv.withValue(new SimpleDateFormat("yyyy-dd-MM HH:mm:ss")) {
   // safely use the Thread-bound instance, but this is a new one each time arrrggggg
   dateFormatDv.value.format(new Date(java.util.Date.getTime()))
 }

你想做的可以这样做:

  Future {
    dateFormatDv.withValue(new SimpleDateFormat("yyyy-dd-MM HH:mm:ss")) {
      doStuffWithDateFormat(dateFormatDv.value)
      doMoreStuffWithTheSameFormatInstance(dateFormatDv.value)
    }          
  }

  Future {
    dateFormatDv.withValue(new SimpleDateFormat("yyyy-dd-MM HH:mm:ss")) {
      useADifferentInstanceOfDateFormat(dateFormat.value)
    }
  }

至于默认值,只是让你设置,方便在当前线程使用,不用.withValue

 doSomethingWithDefaultFormatInstance(dateFormat.value)

我猜 Scala 的 DynamicVariableThreadLocal 化更像这样:

// do only once and put in static scope within some Object
val dateFormatDv = new DynamicVariable[Option[SimpleDateFormat]](None)

// this is executed by different threads
def formatTimestamp(timestamp: Long): String = {
  dateFormatDv.value match {
    case None => dateFormatDv.value_=(Some(new SimpleDateFormat("yyyy-dd-MM HH:mm:ss")))
  }
  // safely use the Thread-bound instance
  dateFormatDv.value.map(_.format(new Date(timestamp))).get
}