【发布时间】: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 的问题,是否会在以后的任何版本中修复?
【问题讨论】:
-
我知道 scala 2.10 在其反射库中存在线程安全问题,但听起来这些问题应该在 2.11 中修复:docs.scala-lang.org/overviews/reflection/thread-safety.htmlgithub.com/xitrum-framework/xitrum/issues/155
-
我现在也在 scala 2.12.8(以及相应的 scala-reflect 依赖项)中复制了这种行为。
标签: java multithreading scala