【问题标题】:Scala DynamicVariable's replacement of ThreadLocalScala DynamicVariable 对 ThreadLocal 的替换
【发布时间】:2017-04-25 18:23:12
【问题描述】:

看不懂DynamicVariable背后的代码和逻辑:

  • 首先你创建一个带有默认值的DynamicVariable实例......一个默认值???你想要每个线程的值!这是否意味着您可能在所有线程之间共享相同的默认值?违背了目的……或者?
  • 然后我在所有示例中看到 withValue 几乎每次都创建一个新实例,或者?

例如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()))
 }

【问题讨论】:

    标签: java scala thread-local


    【解决方案1】:

    你想做的可以这样做:

      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)
    

    【讨论】:

    • 你的意思是,如果同一个线程多次执行dateFormatDv.withValue这一行,那么第一次只会创建SimpleDateFormat的一个实例,并在以后的每次执行中重复使用?
    • 不,我的意思是,您执行一次.withValue,然后该块中的所有内容都会看到该值。
    • 但这就是重点,您有许多传入线程正在执行.withValue 及以上,而ThreadLocal 的重点是每个线程都有一个可重用的单独实例,而不仅仅是创建一个新实例每一次。所以你写的这段代码和我写的不是100%一样。
    • 是的,很多线程都在做.withValue(new Foo) { ... },每个线程在{} 中都有自己的实例Foo。这正是你所描述的
    • 啊,好吧...我需要对其进行测试以确保 :) 但我现在接受...
    【解决方案2】:

    我猜 Scala 的 DynamicVariableThreadLocalification 会更像这样:

    // 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
    }
    

    【讨论】:

    • 是的,它与.withValue 相同,只是不那么惯用。您也可以改用ThreadLocal
    猜你喜欢
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 2015-10-09
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    相关资源
    最近更新 更多