【问题标题】:Thread Safety in Scala reflection with type matching具有类型匹配的 Scala 反射中的线程安全
【发布时间】:2019-08-04 15:26:57
【问题描述】:

在 scala 2.11.12、JDK 1.8.0_131 中工作,我已经能够使用以下代码复制在 Apache Spark 中观察到的线程安全错误,其中我反复检查多个线程是否可以通过以下方式匹配 Option[Int] <:<Option[_]

package stuff

import java.util.concurrent.{Executors, Future}

import scala.collection.mutable.ListBuffer

object Main {
  val universe: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe
  import universe._

  def mirror: universe.Mirror = {
    universe.runtimeMirror(Thread.currentThread().getContextClassLoader)
  }

  def localTypeOf[T: TypeTag]: `Type` = {
    val tag = implicitly[TypeTag[T]]
    tag.in(mirror).tpe.dealias
  }

  def matcher[T: TypeTag]: Boolean = {
    val typ = localTypeOf[T]
    typ.dealias match {
      case t if t <:< localTypeOf[Option[_]] =>
        true
      case _ =>
        false
    }
  }

  def main(args: Array[String]): Unit =  {
    val executor = Executors.newFixedThreadPool(5)

    try {
      val futures = new ListBuffer[Future[_]]()

      for (i <- 1 to 10) {
        futures += executor.submit(new Runnable {
          override def run(): Unit = {
            if (Main.matcher[Option[Int]]) {
              println("ALL OK")
            } else {
              throw new Exception("THIS SHOULD BE IMPOSSIBLE!!!!!!")
            }
          }
        })
      }

      futures.foreach(_.get())
    } finally {
      executor.shutdown()
    }
  }
}

此代码应始终打印“一切正常”,但有时(约 5% 的机会)它实际上会抛出“这应该是不可能的”错误,并带有以下堆栈跟踪:

Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.Exception: THIS SHOULD BE IMPOSSIBLE!!!!!!
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at stuff.Main$$anonfun$main$2.apply(Main.scala:81)
at stuff.Main$$anonfun$main$2.apply(Main.scala:81)
at scala.collection.immutable.List.foreach(List.scala:392)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
at scala.collection.mutable.ListBuffer.foreach(ListBuffer.scala:45)
at stuff.Main$.main(Main.scala:81)
at stuff.Main.main(Main.scala)
Caused by: java.lang.Exception: THIS SHOULD BE IMPOSSIBLE!!!!!!
at stuff.Main$$anonfun$main$1$$anon$1.run(Main.scala:75)

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)ALL OK

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
  • 为什么?
  • 我可以在我的程序中进行更改以解决此问题吗?
  • 如果这是 scala 的问题,是否会在以后的任何版本中修复?

【问题讨论】:

标签: java multithreading scala


【解决方案1】:
  • 为什么? 原来是 scala 反射本身的一个已知线程安全错误 https://github.com/scala/bug/issues/10766
  • 我可以在我的程序中更改什么来解决此问题吗? 在尝试了几件事后,它可以将每个 &lt;:&lt; 调用包装在一个同步块中。仍然有兴趣知道是否有人有更优雅的方式来做到这一点。
  • 如果这是 scala 的问题,是否会在任何未来版本中修复? 不,它存在于所有当前版本的 scala 中(通过2.13.0-M5)(请参阅上述 scala 问题)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2020-08-23
    • 1970-01-01
    • 2017-02-25
    • 2011-07-16
    • 2016-04-02
    相关资源
    最近更新 更多