为什么这个scala by-name参数表现得很奇怪

Har*_*555 3 scala

好吧,这个问题可能不多说,但是这里是交易:我正在学习scala并决定使用一个方法来创建一个实用程序类"FuncThread",该方法接收一个名称参数函数(我想它之所以称之为因为它是一个函数但是没有参数列表)然后启动一个带有runable的线程,然后执行传递的函数,我写了这样一个类,如下所示:

class FuncThread
{
   def runInThread( func: => Unit)
   {
     val thread = new Thread(new Runnable()
     {
        def run()
        {
          func
        }
     }

     thread.start()
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我写了一个junit测试如下:

@Test
def weirdBehaivorTest()
{
  var executed = false
  val util = new FuncThread()
  util.runInThread
  {
    executed = true
  }

  //the next line makes the test pass....
  //val nonSense : () => Unit  = () => { Console println "???" }

  assertTrue(executed)
}
Run Code Online (Sandbox Code Playgroud)

如果我取消注释第二个注释行,则测试通过,但如果它仍然被注释,则测试失败,这是正确的行为吗?by-name参数函数如何以及何时执行?

我知道Scala有actor库但我想尝试这个,因为我一直想用Java做这个

The*_*aul 7

这仅仅是竞争条件吗?runInThread启动线程,但是在另一个线程将其设置为true之前,您的断言测试'已执行'.添加额外的行意味着在测试之前执行更多代码(以及时间),使"执行"更有可能被设置为true

  • 不,你添加了一个睡眠(10)并掩盖了错误,没有修复它. (6认同)
  • @ Harima555事实上,没有内存障碍,例如同步提供的内容,你永远不能保证一个线程所做的更改会被另一个线程看到.查找Java内存模型. (2认同)

Dav*_*ith 5

还值得注意的是(从 Scala 2.8 开始),您尝试编写的构造在标准库中可用

import scala.actors.Futures._

future{
    executed = true
}
Run Code Online (Sandbox Code Playgroud)

这个构造实际上比您所描述的更强大,线程计算可以返回一个值,并且可以等待该值。

import scala.actors.Futures._

//forks off expensive calculation
val expensiveToCalculateNumber:Future[Int] = future{
    bigExpensiveCalculation()  
}

// do a lot of other stuff

//print out the result of the expensive calculation if it's ready, otherwise wait until it is
println( expensiveToCalculateNumber());
Run Code Online (Sandbox Code Playgroud)