【发布时间】:2019-09-16 19:58:59
【问题描述】:
java.nio.file.Files.createFile 会阻塞调用线程吗?如是,
创建文件/目录的非阻塞异步替代方法是什么?
我正在寻找一个可以在 java 或 scala 中工作的简单解决方案。
【问题讨论】:
-
Future(createFile)
标签: java scala asynchronous file-io io
java.nio.file.Files.createFile 会阻塞调用线程吗?如是,
创建文件/目录的非阻塞异步替代方法是什么?
我正在寻找一个可以在 java 或 scala 中工作的简单解决方案。
【问题讨论】:
Future(createFile)
标签: java scala asynchronous file-io io
Files API 中的所有操作都是阻塞的。执行createFile 非阻塞方式的唯一方法是使用某种并发包装器,它将在其他线程上执行该操作。
例如,您可以使用 scala 标准库中的 Future:
import scala.concurrent.Future
import scala.concurrent.blocking
import scala.util.{Failure, Success}
object BlockingIOExecutionContext {
implicit val ec: ExecutionContextExecutor = ExecutionContext.fromExecutor(
Executors.newCachedThreadPool()
) // create seperate thread pool for our blocking operations
}
import BlockingIOExecutionContext._ //importing our execution context for blocking operations
// alternatively if you're doing only very few IO calls just use default ExecutionContext
// import scala.concurrent.ExecutionContext.Implicits.global
val createFileFuture: Future[Path] = Future {
blocking { //mark this operation as blocking
Files.createFile(Paths.get("hello"))
}
}
createFileFuture
.map(_.getParent) // Future is monad, so you can use map/flatMap
.onComplete{
case Success(parentsPath) => /* do something when file is created */
case Failure(exception) => /* do something when creation fails */
}
当您执行大量阻塞 IO 操作时,最好使用单独的线程池。
使用内部 blocking 块也是一种很好的做法,因为它让 ExecutionContext 知道您正在执行阻塞操作。如果您一次要执行更多阻塞调用,ExecutionContext 可以决定向线程池添加更多线程。
请查看此article,了解有关使用 scala 期货的更多提示。
还有其他替代方案,例如 cats-io、scalaz zio 或 monix task,但如果您不使用其中任何一个我会留在Future。
【讨论】:
Files.createFile是Java IO库。据我所知,文件 API 或 JDBC 之类的所有 Java IO 库都是阻塞的,所以唯一的方法是让async 是通过 shifting 到另一个线程。 Future 只是一个高级包装器,它使对其他线程的操作更容易。