package a.b.ctrait Oxbow {val Bippy = a.b.c.d.Bippy //I never reference Bippy in the test but this val seems critical. Remove it and the deadlock disappearsdef systemInt = 1def threadName = Thread.currentThread().getName}object Oxbow extends Oxbow
package a.bpackage object c extends Oxbow
package a.b.cpackage dobject Bippy {private[this] val lakes = {Thread.sleep(500) //the sleep is important in revealing the deadlocksystemInt //this call is important. Remove it and the deadlock disappears}}
"ForkJoinPool-1-worker-9" daemon prio=6 tid=0x0000000014630800 nid=0x1940 in Object.wait() [0x000000001543e000]
java.lang.Thread.State: RUNNABLE
at a.b.c.Oxbow$class.$init$(Oxbow.scala:4)
at a.b.c.package$.<init>(package.scala:3)
at a.b.c.package$.<clinit>(package.scala)
at test.Test1$$anonfun$bar$1$$anonfun$apply$1.apply$mcV$sp(Test1.scala:12)
at test.Test1$$anonfun$bar$1$$anonfun$apply$1.apply(Test1.scala:9)
at test.Test1$$anonfun$bar$1$$anonfun$apply$1.apply(Test1.scala:9)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at scala.concurrent.impl.ExecutionContextImpl$$anon$3.exec(ExecutionContextImpl.scala:107)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
"ForkJoinPool-1-worker-11" daemon prio=6 tid=0x000000001462c000 nid=0x2a1c in Object.wait() [0x0000000014fcd000]
java.lang.Thread.State: RUNNABLE
at a.b.c.d.Bippy$.<init>(Bippy.scala:8)
at a.b.c.d.Bippy$.<clinit>(Bippy.scala)
at a.b.c.Oxbow$class.$init$(Oxbow.scala:4)
at a.b.c.Oxbow$.<init>(Oxbow.scala:13)
at a.b.c.Oxbow$.<clinit>(Oxbow.scala)
at test.Test2$$anonfun$foo$1$$anonfun$apply$1.apply$mcV$sp(Test2.scala:13)
at test.Test2$$anonfun$foo$1$$anonfun$apply$1.apply(Test2.scala:10)
at test.Test2$$anonfun$foo$1$$anonfun$apply$1.apply(Test2.scala:10)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at scala.concurrent.impl.ExecutionContextImpl$$anon$3.exec(ExecutionContextImpl.scala:107)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
package testimport scala.concurrent.Futureimport java.util.concurrent.CountDownLatchobject Main extends App {object Test1 {import a.b.c._def bar() = (0 until 100000) map { i =>import scala.concurrent.ExecutionContext.Implicits.globalFuture {val s = i.toString + "1"if (i % 100 == 0) {println(s + " from " + threadName)}}}}object Test2 {import a.b.c.Oxbow._ //notice I get threadName here differently. if this is changed to "import a.b.c._" the deadlock disappearsdef foo() = (0 until 100000) map { i =>import scala.concurrent.ExecutionContext.Implicits.globalFuture {val s = i.toString + "2"if (i % 100 == 0) {println(s + " from " + threadName)}}}}import scala.concurrent.ExecutionContext.Implicits.globalval l = new CountDownLatch(2)//Note I seem to need to declare these two threads, rather than just sequence the two seqs of futures to reveal the deadlocknew Thread(new Runnable {def run() {Future.sequence(Test1.bar()) onComplete { case _ => l.countDown()}}}).start()new Thread(new Runnable {def run() {Future.sequence(Test2.foo()) onComplete { case _ => l.countDown()}}}).start()l.await()}
You are best off looking at the byte code to figure object deadlocks out coupled with the byte code location.
Been bitten by similar package object problems before, never fun to figure out. Still guess is that the val is initialized in Bippy but also by D, two threads both hit lazy loading and depend on the other to fit. The locations in the byte code would reveal where. But you already know how to work around it :)
--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.