如何比较以前的列表并在多线程中更新字段

How to compare a previous list and updated a field in multi thread

我有一个本地缓存,用于存储跑步者的圈速信息,我需要在显示当前圈速信息的同时显示跑步者当前的圈速是好还是差。

data class RunInfo(
    val runnerId: String,
    val lapTime: Double,
    var betterThanLastLap: BETTERTHANLASTLAP
)

enum class BETTERTHANLASTLAP {
    NA, YES, NO
}

object RunDB {

    private var listOfRunners: MutableList<RunInfo> =
        java.util.Collections.synchronizedList(mutableListOf())
    private var previousList: MutableList<RunInfo> = mutableListOf()

    fun save(runList: MutableList<RunInfo>) {
        previousList = listOfRunners.toMutableList()
        listOfRunners.clear()
        listOfRunners.addAll(runList)
        listOfRunners.forEach { runner ->
            previousList.forEach { previousLap ->
                if (runner.runnerId == previousLap.runnerId) {
                    runner.betterThanLastLap =
                        when {
                            previousLap.lapTime == 0.0 -> BETTERTHANLASTLAP.NA
                            runner.lapTime >= previousLap.lapTime -> BETTERTHANLASTLAP.YES
                            else -> BETTERTHANLASTLAP.NO
                        }
                }
            }
        }
    }
}

这似乎可以完成工作,但我经常遇到并发修改异常。有没有更好的方法解决这个问题?

我不建议将可变列表与读写 var 属性结合使用。以两种不同的方式使其可变会产生歧义并且容易出错。由于您只是清除和替换列表内容,我会将其设为只读列表和读写列表 属性.

您需要同步整个函数,这样它一次只能执行一次。

object RunDB {

    private var listOfRunners: List<RunInfo> = listOf()
    private var previousList: List<RunInfo> = listOf()

    fun save(runList: List<RunInfo>) {
        sychronized(this) {
            previousList = listOfRunners.toList()
            listOfRunners = runList.toList()
            listOfRunners.forEach { runner ->
                previousList.forEach { previousLap ->
                    if (runner.runnerId == previousLap.runnerId) {
                        runner.betterThanLastLap =
                            when {
                                previousLap.lapTime == 0.0 -> BETTERTHANLASTLAP.NA
                                runner.lapTime >= previousLap.lapTime -> BETTERTHANLASTLAP.YES
                                else -> BETTERTHANLASTLAP.NO
                            }
                    }
                }
            }
        }
    }
}

在您正在复制和移动的这些列表中有可变数据 class 也让人感觉容易出错。我建议使其不可变:

data class RunInfo(
    val runnerId: String,
    val lapTime: Double,
    val betterThanLastLap: BETTERTHANLASTLAP
)

object RunDB {

    private var listOfRunners: List<RunInfo> = listOf()
    private var previousList: List<RunInfo> = listOf()

    fun save(runList: List<RunInfo>) {
        sychronized(this) {
            previousList = listOfRunners.toList()
            listOfRunners = runList.map { runner ->
                val previousLap = previousList.find { runner.runnerId == previousLap.runnerId }
                runner.copy(betterThanLastLap = when {
                    previousLap == null || previousLap.lapTime == 0.0 -> BETTERTHANLASTLAP.NA
                    runner.lapTime >= previousLap.lapTime -> BETTERTHANLASTLAP.YES
                    else -> BETTERTHANLASTLAP.NO
                })
            }
        }
    }
}