当前位置: 首页 > 知识库问答 >
问题:

通过改装实现Thread安全

温源
2023-03-14

我仍然有一点困难把所有关于使用协程启动网络请求的线程安全的信息放在一起。

假设我们有以下用例,有一个我们获得的用户列表,对于其中的每个用户,我将进行一些特定的检查,这些检查必须通过对API的网络请求来运行,并向我返回有关该用户的一些信息。

userCheck发生在一个库中,它不公开挂起函数,但仍然使用回调。在这个库中,我看到了这样的代码来启动每个网络请求:

internal suspend fun <T> doNetworkRequest(request: suspend () -> Response<T>): NetworkResult<T> {
    return withContext(Dispatchers.IO) {
        try {
            val response = request.invoke()
            ...

根据文件,调度员。IO可以使用多个线程来执行代码,而且请求函数只是来自改装API的函数。

因此,我所做的是为每个用户启动请求,并使用单个resultHandler对象,该对象将结果添加到列表中,并检查结果列表的长度是否等于用户列表的长度,如果是,则完成所有用户检查,我知道我可以对结果做些什么,这些结果需要一起返回。

val userList: List<String>? = getUsers()
val userCheckResultList = mutableListOf<UserCheckResult>()
val handler = object : UserCheckResultHandler {
                  override fun onResult(
                        userCheckResult: UserCheckResult?
                  ) {
                        userCheckResult?.let {
                            userCheckResultList.add(
                                it
                            )
                        }
                        if (userCheckResultList.size == userList?.size) {
                            doSomethingWithResultList()
                            print("SUCCESS")
                        }
                    }
                }

userList?.forEach {
    checkUser(it, handler)
}

我的问题是:这个实现是线程安全的吗?据我所知,Kotlinhtml" target="_blank">对象应该是线程安全的,但我得到的反馈是,这可能不是最好的实现:D

但从理论上讲,即使请求同时异步和多个启动,一次也只有一个可以访问结果处理程序运行的线程的锁,并且不会有竞争条件或将项目添加到列表和比较大小的问题。

我错了吗?有没有更好的方法来处理这种情况?

共有1个答案

傅经业
2023-03-14

如果您并行执行多个请求-它不是。List不是线程安全的。但它很简单。创建一个Mutex对象,然后将您对list的操作打包为锁,如下所示:

val lock = Mutex()
val userList: List<String>? = getUsers()
val userCheckResultList = mutableListOf<UserCheckResult>()
val handler = object : UserCheckResultHandler {
                  override fun onResult(
                        userCheckResult: UserCheckResult?
                  ) {
                        lock.withLock {
                            userCheckResult?.let {
                                userCheckResultList.add(
                                    it
                                )
                            }
                            if (userCheckResultList.size == userList?.size) {
                                doSomethingWithResultList()
                                print("SUCCESS")
                            }
                        }
                    }
                }

userList?.forEach {
    checkUser(it, handler)
}

我必须补充一点,这个整个解决方案看起来非常粗鲁。我会走完全不同的路线。运行所有包装在async{//network Request}中的请求,这将返回Deferred对象。将此对象添加到某个列表中。之后使用waitAll()等待所有这些延迟对象。像这样:

val jobs = mutableListOf<Job>()
userList?.forEach {
   // i assume checkUser is suspendable here
   jobs += async { checkUser(it, handler) }
}

// wait for all requests
jobs.awaitAll()

// After that you can access all results like this:
val resultOfJob0 = jobs[0].getCompleted()
 类似资料:
  • 提示:Bower 是一个前端资源包管理工具,使用它可以方便的下载和管理前端包资源。如果你暂时没有用到 Bower,可以跳过本文。注意:Bower 已经停止维护,不建议继续使用 Bower 安装 Highcharts。 我们提供的 Bower 包,包含了 Highcharts、Highstock、Highmaps 及相关的 js 文件,通过以下命令即可安装 bower install highcha

  • 提示:npm 是 nodejs 包管理工具,可以方便的管理和使用 nodejs 包,如果你暂时没有用到,可以跳过本文。 我们提供的 Highcharts npm 包,包含了 Highcharts、Highstock、Highmaps 及所有的功能模块,通过下面的命令即可完成安装 npm install highcharts --save 1. 加载  Highcharts var Highcha

  • 问题内容: 以下是我运行时遇到的错误: 问题答案: 在没有空格的路径中创建您的virtualenv环境。这就是为什么它发生的原因: 创建环境时,它会建立一个目录。在该目录中是与环境有关的所有可执行文件。有些是脚本。如您所知,hashbang用来告诉系统使用什么解释程序来运行脚本。您可能经常在脚本顶部看到此信息: 如果脚本位于,则告诉系统运行以下命令来执行脚本: 就您而言,virtualenv正在创

  • 本文向大家介绍python实现通过shelve修改对象实例,包括了python实现通过shelve修改对象实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了python实现通过shelve修改对象的方法,分享给大家供大家参考。 具体实现方法如下: 本文实例测试环境为Python2.7.6 程序运行结果如下: 实例代码及运行结果均配有较为详尽的注释,帮助大家理解其含义。希望本文所述对大家的

  • 问题内容: 我正在尝试在Ubuntu PC上使用composer安装laravel安装程序,但是在安装过程中出现此错误。您的要求无法解决为一组可安装的软件包。 出现错误,然后我使用此注释: 问题答案: 它说它需要 zip扩展名 laravel / installer v1.4.0需要ext-zip ........ 安装与已安装的php版本相对应的版本:

  • 本文向大家介绍python通过pip更新所有已安装的包实现方法,包括了python通过pip更新所有已安装的包实现方法的使用技巧和注意事项,需要的朋友参考一下 较新的pip已经支持list --outdated了,所以记录一下新的方法: format有两个选项,一个是legacy,一个是columns。后者会带一个表头: Package        Version Latest Type ---