Java 在另一个线程中使用从一个线程创建的Outputstream安全吗?
在我的scala代码中,我从我的主函数创建了一个GzipOutputStream对象,并在将来使用它,它在每个循环中被调用。在迭代中开始未来之前,等待上一个迭代的未来。因此,不同线程永远不会同时访问GzipOutputStream对象。但是,我注意到该程序有时会生成损坏的zip文件。所以,我的问题是,如果不同时使用来自不同线程的GzipOutputStream对象,是否安全 基本上,以下是pseducodeJava 在另一个线程中使用从一个线程创建的Outputstream安全吗?,java,multithreading,scala,Java,Multithreading,Scala,在我的scala代码中,我从我的主函数创建了一个GzipOutputStream对象,并在将来使用它,它在每个循环中被调用。在迭代中开始未来之前,等待上一个迭代的未来。因此,不同线程永远不会同时访问GzipOutputStream对象。但是,我注意到该程序有时会生成损坏的zip文件。所以,我的问题是,如果不同时使用来自不同线程的GzipOutputStream对象,是否安全 基本上,以下是pseducode gzos = new GzipOutputStream(...) .... for lo
gzos = new GzipOutputStream(...)
....
for loop:
f = future(futureFunction)
....
waitFor(f)
gzos.close
def futureFunction(...)
...
gzos.write(...)
...
GzipOutputStream是一个有状态对象。仅仅一个接一个地运行任务是不够的。对于正确的工作,您需要第一次迭代所做的更改对执行第二次迭代的线程可见。
基本上,您需要一个关系“第一次迭代的结束”发生在“第二次迭代的开始”之前
我不确定这种关系是否适用于任意执行上下文。
但如果您使用单线程执行上下文,这显然是正确的。您可能会发现akka streams非常适合解决此问题
import akka.stream.scaladsl._
import akka.stream._
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
val runnable: Future[IOResult] =
Source(1 to 10)
.mapAsync(1)(i => Future.successful(i))
.map(s => ByteString(s + "\n"))
.via(Compression.gzip)
.runWith(FileIO.toPath(Paths.get("out.gz")))
val result = Await.result(runnable, 10.seconds)
有关更多信息,请参见如果您将其声明为最终或易失性,则它是安全的。我打赌损坏的zip文件还有其他原因。是的,在我的代码中,第一次迭代总是在第二次迭代之前发生,正如你从我给出的伪代码中看到的那样。基本上,n+1未来总是在n未来结束后开始执行。我的意思是,作为JVM概念,在之前发生。默认情况下,不能保证一个线程可以看到另一个线程所做的更改,即使您知道这些更改是一个接一个地运行的。