multithreading - Implicit class holding mutable variable in multithreaded environment
问题描述
I need to implement a parallel
method, which takes two computation blocks, a
and b
, and starts each of them in a new thread. The method must return a tuple with the result values of both the computations. It should have the following signature:
def parallel[A, B](a: => A, b: => B): (A, B)
I managed to solve the exercise by using straight Java-like approach. Then I decided to make up a solution with implicit class. Here's it:
object ParallelApp extends App {
implicit class ParallelOps[A](a: => A) {
var result: A = _
def spawn(): Unit = {
val thread = new Thread {
override def run(): Unit = {
result = a
}
}
thread.start()
thread.join()
}
}
def parallel[A, B](a: => A, b: => B): (A, B) = {
a.spawn()
b.spawn()
(a.result, b.result)
}
println(parallel(1 + 2, "a" + "b"))
}
For unknown reason, I receive output (null,null)
. Could you please point me out where is the problem?
解决方案
剧透警报:这并不复杂。这很有趣,就像魔术一样(如果您考虑阅读有关 Java 内存模型“有趣”的文档,那就是)。如果您还没有弄清楚,我强烈建议您尝试弄清楚,否则不会很有趣。有人应该从中得出一个“除以零证明 2 = 4”的谜题。
考虑以下较短的示例:
implicit class Foo[A](a: A) {
var result: String = "not initialized"
def computeResult(): Unit = result = "Yay, result!"
}
val a = "a string"
a.computeResult()
println(a.result)
运行时,它会打印
not initialized
尽管我们调用computeResult()
并设置result
为"Yay, result!"
. 问题是这两个调用属于两个完全独立的a.computeResult()
实例。隐式转换执行了两次,第二个隐式创建的对象对第一个隐式创建的对象的更改一无所知。它与线程或 JMM 完全无关。a.result
Foo
顺便说一句:您的代码不是并行的。调用join
后立即调用start
不会给您带来任何好处,您的主线程只会闲置并等待另一个线程完成。绝不会有两个线程同时做任何有用的工作。
推荐阅读
- typescript - 保证数组/集合具有来自 Typescript 中字符串联合的所有值
- spring-security - MUnit 和 Spring 安全模式的问题
- android - 当其他用户使用我的应用程序(Firebase,android)时,我的列表视图会自动填充
- python - 如何构建 gremlin 查询以添加和删除顶点作为第一部分事务
- reactjs - 导入 css 的 npm 依赖项的 Next.js 错误
- c# - 有没有办法使用 IoC 容器将依赖项注入到帮助程序类?
- javascript - 为什么这个导出的 typescript const 不能从转译和捆绑的代码中导入?
- css - 在 Angular 7 中创建滚动导航
- javascript - MySQL 事务与垃圾邮件
- node.js - nodejs中如何使用sinon进行中间件测试?