Что я хочу сделать, это использовать Future
, чтобы открыть поток для обработки задачи async, которая может быть вызвана часто.Scala Будущее не работает, как я ожидаю
Но в async task
. Я также вызываю две функции Future
, чтобы получить информацию из разных источников данных.
Я пишу программу для имитации этой ситуации.
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Success, Failure}
import scala.util.control.Breaks
import ExecutionContext.Implicits.global
object AsyncTest {
def main(args: Array[String]) {
try {
println("Run...")
aSyncTask
} catch {
case e => e.printStackTrace()
}
Thread.sleep(999999)
}
//dataSource1
def getInfo1 : Future[String] = Future{
"A"
}
//dataSource2 let it wait 3 seconds...
def getInfo2 : Future[String] = Future{
Thread.sleep(3000)
"B"
}
def aSyncTask = Future{
getInfo1
getInfo2
var result1 : String = null
var result2 : String = null
getInfo1.onComplete{
case Success(value) => result1 = value
case Failure(t) => println {
"An error has occured: " + t.getMessage
}
}
getInfo2.onComplete{
case Success(value) => result2 = value
case Failure(t) => println {
"An error has occured: " + t.getMessage
}
}
/*I want to wait both Future function completed then
I can do some business logic */
Breaks.breakable{
while (true) {
if (result1 != null && result2 != null)
Breaks.break
}
}
println("----------------------")
println("result1:"+result1)
println("result2:"+result2)
println("----------------------")
}
}
После того как я компиляции и запуска этой программы, она выдавала ничего. просто подождите.
Run...
Я ожидал, что я мог видеть выход:
Run...
----------------------
result1:A
result2:B
----------------------
Итак, я добавил код в while
цикле для отладки.
Breaks.breakable{
while (true) {
println(result1)
println(result2)
if (result1 != null && result2 != null)
Breaks.break
}
}
Тогда выход:
Run...
A
null
A
null
A
null
A
null
A
null
(After 3 seconds...)
A
B
----------------------
result1:A
result2:B
----------------------
Что происходит ?? Я просто добавлю два println
, чтобы увидеть две переменные.
Почему программа может быть выполнена так, как я ожидал, когда я ее печатаю?
Вы должны прочитать о параллельности и синхронизации. Такие вещи, как 'result2 = value', не так просты, как вы думаете, когда к ним обращаются несколько потоков. Это одна из главных причин, по которой они придумали scala, в первую очередь, где использование изменчивых переменных сильно обескуражено. Чтобы понять, почему ваш код не работает, попробуйте выполнить такие действия, как «volatile variable», «java synchronization», «jvm concurrency» и т. Д. Чтобы исправить это, попробуйте написать его по-другому, не используя изменяемые переменные. – Dima
@Dima Из любопытства вы имеете в виду, что JIT просто оптимизирует его (кеш на уровне нити, который я предполагаю?), Поскольку он не ожидает, что эта переменная изменится? Так что, если я объявлю их '@ volatile', это может сработать? –
Я не знаю, будет ли JIT оптимизировать его, но я не думаю, что это _that_ smart. Проблема в том, что значение переменной, вероятно, находится в регистре (или кэше процессора), и изменения не будут удалены в память до тех пор, пока не будет поврежден барьер памяти ('println' скорее всего создает один из них как побочный эффект, и поэтому вещи «таинственно» начинают работать, когда они добавляются). Да, в этом конкретном случае, объявляя, что vars 'volatile', вероятно, заставит его работать. Я бы не сказал, что это - путь к исправлению проблемы с этим кодом. – Dima