所以我有这个实验性的代码:

    class WorkLoader : Runnable {
    private val id : Int
    private val listener : Listener?
    private val lock : ReentrantLock
    private val condition : Condition
    private val counter : Counter?

    private var isFinished : Boolean

    constructor(counter: Counter? = null, listener: Listener? = null) {
        id = IdGenerator.getId()
        isFinished = false
        lock = ReentrantLock()
        condition = lock.newCondition()
        this.counter = counter
        this.listener = listener
    }

    interface Listener {
        fun onWorkStarted(id : Int)
        fun onWorkFinished(id : Int, s : String, elapsed : Long)
    }

    override fun run() {
        listener?.onWorkStarted(id)
        val startTime = System.currentTimeMillis()

        //The loop below just simply loads the CPU with useless stuff, it does nothing important
        var s = ""
        for (i in 1 .. 10_000_000) {
            counter?.add()
            val c : Char = (i % 95 + 32).toChar()
            s += c
            if (s.length > 200) {
                s = s.substring(1)
            }
        }

        val elapsedTime = System.currentTimeMillis() - startTime
        listener?.onWorkFinished(id, s, elapsedTime)

        lock.lock()
        isFinished = true
        condition.signal()
        lock.unlock()
    }

    fun waitTillFinished() {
        lock.lock()
        while (!isFinished) {
            condition.await()
        }
        lock.unlock()
    }
}

以及在6个独立线程中同时运行6个WorkLoader实例的主函数:

    fun main(arguments: Array<String>) {
    println("Hello World!")

    val workListener = WorkLoaderListener()
    
    val workers = ArrayList<WorkLoader>()
    for (i in 1..6) {
        val workLoader = WorkLoader(counter = null, workListener)
        workers.add(workLoader)

        val thread = Thread(workLoader)
        thread.start()
    }

    for (worker in workers) {
        worker.waitTillFinished()
    }
    
    println("End of main thread")
}

class WorkLoaderListener : WorkLoader.Listener {

    override fun onWorkStarted(id: Int) {
        println("Work started, id:$id ${getFormattedTime()}")
    }

    override fun onWorkFinished(id: Int, s: String, elapsed : Long) {
        println("Work ENDED,   id:$id ${getFormattedTime()}, in ${elapsed/1000} s")
    }
}

让所有6个线程完成执行需要8秒.以下是输出:

Hello World!
Work started, id:1 21:12:26.577
Work started, id:0 21:12:26.577
Work started, id:2 21:12:26.577
Work started, id:4 21:12:26.577
Work started, id:5 21:12:26.577
Work started, id:3 21:12:26.577
Work ENDED,   id:2 21:12:35.137, in 8 s
Work ENDED,   id:1 21:12:35.137, in 8 s
Work ENDED,   id:3 21:12:35.215, in 8 s
Work ENDED,   id:0 21:12:35.215, in 8 s
Work ENDED,   id:5 21:12:35.215, in 8 s
Work ENDED,   id:4 21:12:35.231, in 8 s
End of main thread

然而!单独线程中只有1个WorkLoader实例在1秒内执行.这使得一个接一个地运行这些线程而不是同时运行它们变得更高效. 就像这样:

for (i in 1..6) {
    val workLoader = WorkLoader(counter = null, workListener)
    workers.add(workLoader)

    val thread = Thread(workLoader)
    thread.start()
    //just one extra line to wait for the termination before starting another workLoader
    workLoader.waitTillFinished() //I understand that the workLoader thread might still be running when this method returns, 
// but it doesn't matter, the thread is about to die anyway
}

输出:

Hello World!
Work started, id:0 21:23:33.622
Work ENDED,   id:0 21:23:35.411, in 1 s
Work started, id:1 21:23:35.411
Work ENDED,   id:1 21:23:36.545, in 1 s
Work started, id:2 21:23:36.545
Work ENDED,   id:2 21:23:37.576, in 1 s
Work started, id:3 21:23:37.576
Work ENDED,   id:3 21:23:38.647, in 1 s
Work started, id:4 21:23:38.647
Work ENDED,   id:4 21:23:39.687, in 1 s
Work started, id:5 21:23:39.687
Work ENDED,   id:5 21:23:40.726, in 1 s
End of main thread

因此,在这种情况下,整个程序的执行大约在6到7秒内结束.我有一个带有12个逻辑线程的6核英特尔CPU.所以我希望所有6个线程在最多2秒内执行(当同时启动所有线程时).在第一种情况下(同时所有线程),CPU利用率达到100%,并且在整个执行时间都保持在那里.在第二种情况下(一次一个线程),CPU在短时间内达到47%,整个执行速度略快.

那么,多线程有什么意义呢?为什么会发生这种事?感觉拥有超过1个工作线程是没有意义的,因为任何额外的线程都会使所有其他线程变慢,无论您拥有多少个CPU核心可供支配.如果一个线程能够使用CPU的所有核心,那么为什么在第二种情况下,我的CPU没有达到100%的负载?

推荐答案

@Tenour04,谢谢!你的 comments 把我引向了正确的答案.多线程的用途节省了! 所以,显然我的字符串操作确实不是多线程友好的,不知道为什么. 因此,我将CPU加载代码更改为:

val cArr = arrayOfNulls<Char>(200)
for (i in 1..20_000_000) {
    val cValue: Char = (i % 95 + 32).toChar()
    if (cArr[0] == null) {
        cArr[0] = cValue
    } else {
        var tempC = cValue
        for (ci in cArr.indices) {
            val temp = cArr[ci]
            cArr[ci] = tempC
            if (temp == null) {
                break
            }
            tempC = temp
        }
    }
}

现在,这段代码在3秒内在1个线程上执行.正如您在下面的输出中看到的:

Hello World!
All threads initiated
Work started, id:0 02:16:58.000
Work ENDED,   id:0 02:17:01.189, in 3 s
End of main thread

现在有6个线程:

Hello World!
All threads initiated
Work started, id:0 02:18:48.830
Work started, id:2 02:18:48.830
Work started, id:1 02:18:48.830
Work started, id:5 02:18:48.830
Work started, id:4 02:18:48.830
Work started, id:3 02:18:48.830
Work ENDED,   id:1 02:18:53.090, in 4 s
Work ENDED,   id:0 02:18:53.168, in 4 s
Work ENDED,   id:3 02:18:53.230, in 4 s
Work ENDED,   id:4 02:18:53.246, in 4 s
Work ENDED,   id:2 02:18:53.340, in 4 s
Work ENDED,   id:5 02:18:53.340, in 4 s
End of main thread

6倍的工作量,但它只增加了1秒的总执行和等待,我的CPU有12个逻辑线程,所以...

Hello World!
All threads initiated
Work started, id:1 02:22:43.299
Work started, id:8 02:22:43.299
Work started, id:3 02:22:43.299
Work started, id:5 02:22:43.299
Work started, id:7 02:22:43.299
Work started, id:9 02:22:43.299
Work started, id:11 02:22:43.299
Work started, id:10 02:22:43.299
Work started, id:0 02:22:43.299
Work started, id:2 02:22:43.299
Work started, id:4 02:22:43.299
Work started, id:6 02:22:43.299
Work ENDED,   id:4 02:22:50.115, in 6 s
Work ENDED,   id:11 02:22:50.132, in 6 s
Work ENDED,   id:7 02:22:50.148, in 6 s
Work ENDED,   id:1 02:22:50.148, in 6 s
Work ENDED,   id:6 02:22:50.148, in 6 s
Work ENDED,   id:9 02:22:50.148, in 6 s
Work ENDED,   id:10 02:22:50.163, in 6 s
Work ENDED,   id:5 02:22:50.163, in 6 s
Work ENDED,   id:0 02:22:50.179, in 6 s
Work ENDED,   id:8 02:22:50.195, in 6 s
Work ENDED,   id:2 02:22:50.195, in 6 s
Work ENDED,   id:3 02:22:50.210, in 6 s
End of main thread

现在,如果我超过12个线程,这比我的CPU的逻辑线程数量还多,时间会大大增加,效率会变得很低.我不会在这一行上发布输出,太多行,所以相信我.

Kotlin相关问答推荐

"Kotlin中的表达式

捕捉异常是Kotlin协程中的反模式吗?

如何在不基于数据 map 的情况下将图例添加到lets plot kotlin

在 detekt 配置文件中找不到某些属性

Jetpack Compose 中的连续重组

为什么 Kotlin 在 sumOf 函数 lambda 中默认不将数字视为Int?

测试协程和线程之间的差异,我在kotlin中使用线程时无法得到OOM错误

如何通过 compose 处理剪切区域?

如何从kotlin中的ArrayList中删除所有元素

内联函数导致单元测试代码覆盖率报告出错

java - 如何将函数作为参数从java传递给kotlin方法?

IntentService (kotlin) 的默认构造函数

在 Koin 中提供一个 Instance 作为其接口

如何在使用 Gradle 的 AppEngine 项目中使用 Kotlin

在 Kotlin 中创建非绑定服务

Kotlin - computed var 属性的用处?

Lint 错误:可疑的相等判断:在 Object DiffUtilEquals 中未实现 equals()

可以在函数参数中使用解构吗?

如何在kotlin用mockito模仿lambda

Android Jetpack Compose 中的文本渐变