所以我有这个实验性的代码:
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%的负载?