Java 在另一个线程中使用从一个线程创建的Outputstream安全吗?

Java 在另一个线程中使用从一个线程创建的Outputstream安全吗?,java,multithreading,scala,Java,Multithreading,Scala,在我的scala代码中,我从我的主函数创建了一个GzipOutputStream对象,并在将来使用它,它在每个循环中被调用。在迭代中开始未来之前,等待上一个迭代的未来。因此,不同线程永远不会同时访问GzipOutputStream对象。但是,我注意到该程序有时会生成损坏的zip文件。所以,我的问题是,如果不同时使用来自不同线程的GzipOutputStream对象,是否安全 基本上,以下是pseducode gzos = new GzipOutputStream(...) .... for lo

在我的scala代码中,我从我的主函数创建了一个GzipOutputStream对象,并在将来使用它,它在每个循环中被调用。在迭代中开始未来之前,等待上一个迭代的未来。因此,不同线程永远不会同时访问GzipOutputStream对象。但是,我注意到该程序有时会生成损坏的zip文件。所以,我的问题是,如果不同时使用来自不同线程的GzipOutputStream对象,是否安全

基本上,以下是pseducode

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概念,在之前发生。默认情况下,不能保证一个线程可以看到另一个线程所做的更改,即使您知道这些更改是一个接一个地运行的。