Android多个进程同时写同一个文件,会怎么样?
如题,如果开启两个进程对同一个文件进行写入会怎么样呢? 今人不见古时月,今月曾经照古人
前言
为什么会产生这个想法呢? 最近在研究多进程的东西,那么多进程APP最重要的就是进程间通信以及多进程下保持数据的一致性了。 常用的进程通信有Bundle、Messenger、AIDL以及共享文件。 其他的没有什么疑问,但是文件共享?多个进程同时操作同一份文件(比如写入),难道不会出问题吗?我有点不清楚,于是就有了下面的测试。
测试
启动多进程
写一个程序包名com.howie.multiple_process ,另外在分别在在另外两个进程中启动两个Activity 。 两个进程com.howie.multiple_process:client1 、com.howie.multiple_process:client2 。 在AndroidManifest.xml 中定义两个Activity,分别在两个进程中启动。
<activity
android:name=".view.ClientActivity1"
android:process=":client1" />
<activity
android:name=".view.ClientActivity2"
android:process=":client2" />
两个进程同时对同一份文件进行写入
分别在这两个不同进程的Activity 中操作同一份文件,比如ClientActivity1 写入i am client1 ,ClientActivity2 写入i am client2 。
统一调用写方法
suspend fun writeString(
filePath: String = "${AppUtil.application.cacheDir}/process_test/test.txt",
content: String
) = suspendCancellableCoroutine<Boolean> {
var going = true
it.invokeOnCancellation {
going = false
}
Thread {
if (it.isActive) {
val file = File(filePath)
val parentFile = file.parentFile
if (parentFile == null) {
it.resumeWithException(IllegalAccessException("path error."))
return@Thread
}
if (!parentFile.exists()) {
parentFile.mkdirs()
}
if (!file.exists()) {
file.createNewFile()
}
while (going && it.isActive) {
var filerWriter: FileWriter? = null
var bufWriter: BufferedWriter? = null
try {
filerWriter = FileWriter(file, true)
bufWriter = BufferedWriter(filerWriter)
bufWriter.write(content)
bufWriter.newLine()
} catch (e: IOException) {
e.printStackTrace()
} finally {
bufWriter?.close()
filerWriter?.close()
}
}
it.resumeWith(Result.success(true))
} else {
it.resumeWithException(CancellationException())
}
}.start()
}
ClientActivity1 在启动后调用写入操作
val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
throwable.printStackTrace()
}
GlobalScope.launch(
context = Dispatchers.Main.immediate + coroutineExceptionHandler,
start = CoroutineStart.DEFAULT
) {
writeString(content = "i am client1")
}
ClientActivity2 在启动后调用写入操作
val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
throwable.printStackTrace()
}
GlobalScope.launch(
context = Dispatchers.Main.immediate + coroutineExceptionHandler,
start = CoroutineStart.DEFAULT
) {
writeString(content = "i am client2")
}
猜测
如果两个写入存在影响的话,就会出现两方字符串写入交叉,比如出现如下结果i am i client1 am client2 ; 如果两个进程互斥的话,则应该是不会出现写入交叉的情况。
结果
i am client1
i am client2
i am client1
i am client2
i am client1
i am client2
i am client1
i am client2
i am client1
i am client2
i am client1
i am client2
i am client1
i am client2
....
上述仅仅是列出了一部分,但是证明两个进程同时写入同一份文件时,是互斥的。所以可以考虑使用文件共享进行IPC通信。
那此时又想到了一个问题,SharedPreferences 是Android 中提供的轻量级存储方案,它通过键值对的方式来存储数据,在底层实现上它采用XML文件来存储键值对。为什么它在多进程下会出问题呢? 答:由于系统对它的读/写有一定的缓存策略,即在内存中会有一份SharedPreferences 文件的缓存,因此在多进程模式下,系统对它的读/写就变得不可靠,当面对高并发的读/写访问,Sharedpreferences 有很大几率会丢失数据,因此,如果在多进程下使用SharedPreferences ,则需要保持数据的一致性。。
总结
Android 多个进程同时操作同一份文件是互斥的,所以可以使用使用共享文件进行IPC通信。两个进程通过读/写同一个文件来交换数据,比如A进程把数据写入文件,B进程通过读取这个文件来获取数据。
当然SharedPreferences 在多进程下会存在问题,那么如何在多进程下安全的使用SharedPreferences 呢?下一章(最近可能都会写一些和IPC有关的😂)会进行详细说明,关于多进程下数据一致性的问题。
创作不易,如有帮助一键三连咯🙆?♀?。欢迎技术探讨噢!
|