同步写入文件

时间:2018-07-05 08:04:37

标签: scala concurrency synchronization

我知道在轻松写入文件时会进行同步,但是问题是当有多个文件时,我们要对每个文件进行同步。我编写了这样的代码,使人们容易理解我所说的话

import java.io._
import java.util.concurrent.{ConcurrentHashMap, ConcurrentMap}

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

object Main {

  val lock: ConcurrentMap[String, Boolean] = new ConcurrentHashMap[String, Boolean]()

  def writeToFile(path: String): Unit = {
    while (lock.get(path)) {}
    lock.put(path, true)
    println("write to file " + path)
    Thread.sleep(2000)
    lock.remove(path)
  }

  def main(args: Array[String]): Unit = {
    Future {
      writeToFile("1")
    }
    Future {
      writeToFile("1")
    }
    Future {
      writeToFile("1")
    }
    while (true) {}
  }
}

结果将是:

write to file 1 [sleep 2 seconds]
write to file 1
write to file 1

最后两行同时打印。还有其他解决方案,请告诉我:)谢谢!!!

1 个答案:

答案 0 :(得分:0)

您的操作未正确锁定或原子锁定。虽然一个线程可能刚刚从地图上删除了锁,但是其他两个线程可能同时退出各自的while循环。

此外,空的无限while循环会对您的资源造成不必要的负担。

我将您的锁映射替换为对每个路径都保留Future的映射。该地图仅通过其原子compute方法进行更新。如果在获得null并创建我们的第一个写入前途之前从未写过路径。另一方面,如果该路径之前已写入,则可以链接新的写入操作。我已经使用.map进行了此操作,如果需要,可以进行错误处理。

有关.map.andThen的更多信息,请参见SO: future chaining

import java.util.concurrent.{ConcurrentHashMap, ConcurrentMap}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object concurrent {

  val writeOperations: ConcurrentMap[String, Future[_]] = new ConcurrentHashMap[String, Future[_]]()

  def writeToFile(path: String): Unit = {
    val writeOp = writeOperations.compute(path, (path, future) => {
      if (future == null) {
        Future {
          println("write to file " + path)
          Thread.sleep(2000)
        }
      } else {
        future.map(x => { // you can use x for error handling of previous write operation
          println("write to file " + path)
          Thread.sleep(2000)
        })
      }
    })
  }

  def main(args: Array[String]): Unit = {
    val futures = Seq(
      Future {
        writeToFile("1")
      }, Future {
        writeToFile("1")
      }, Future {
        writeToFile("1")
      }
    )

    futures.foreach(Await.ready(_, Duration.Inf))
    writeOperations.values().forEach( x => Await.ready(x, Duration.Inf))
  }
}