Kotlin(四)掌握基础知识:线程(Thread.kt)详解

Kotlin(一)掌握基础知识:数据、集合、库函数
Kotlin(二)掌握基础知识:字符串和异常处理
Kotlin(三)掌握基础知识:类

  线程是每一种语音不可能绕开的知识点,这章我们就来仔细看下Kotlin中如何使用线程,我们仔细看下Thread.kt文件的实现

package kotlin.concurrent

public fun thread(
    start: Boolean = true,
    isDaemon: Boolean = false,
    contextClassLoader: ClassLoader? = null,
    name: String? = null,
    priority: Int = -1,
    block: () -> Unit
): Thread {
    val thread = object : Thread() {
        public override fun run() {
            block()
        }
    }
    if (isDaemon)
        thread.isDaemon = true
    if (priority > 0)
        thread.priority = priority
    if (name != null)
        thread.name = name
    if (contextClassLoader != null)
        thread.contextClassLoader = contextClassLoader
    if (start)
        thread.start()
    return thread
}

@kotlin.internal.InlineOnly
public inline fun <T : Any> ThreadLocal<T>.getOrSet(default: () -> T): T {
    return get() ?: default().also(this::set)
}

  在包kotlin.concurrent中定义了两个方法

  1. thread
  2. getOrSet

  其中thread方法便是我们创建线程所需要用到的函数;这个函数有6个参数,分别表示:

  1. 第4行,start:默认为true,表示立即运行
  2. 第5行,isDaemon: 默认为false,表示不是守护线程
  3. 第6行,contextClassLoader: 表示在这个线程中加载类/资源的类加载器
  4. 第7行,name:表示线程的名字
  5. 第8行,priority:表示线程的优先级
  6. 第9行,block:表示线程运行的主函数体

   那thread函数返回类型是什么?看下第10行,答案是Thread类,看下这个Thread的实现

public
class Thread implements Runnable

  原来Kotlin中的线程其内部实现也是java中的Thread,那么他的线程的状态,线程的终止等等肯定都符合java的标准了

从第11行到27行,就是thread方法的函数体了

   那第9行中的block既然表示线程运行的主函数体,那它是怎么被执行的? 为了知晓这个问题的答案,我们首先得了解lambdar表达式

  lambdar表达式一般当参数类型是一个函数的时候,就可以使用它来简化代码的编写 (高阶函数的含义为:一个将另一个函数作为参数或者返回值的函数)

其完整语法为:

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }

其含义为:
定义一个变量sum,其类型是lambda表达式
位于->的左边,(Int, Int)为lambda表达式的参数,分别为两个整形,
位于->的右边,Int表示lambda表达式的返回类型
{}表示lambda的函数体

  在kotlin中,如果参数如果函数的最后一个参数是函数,那么作为相应参数传入的 lambda 表达式可以放在圆括号之外,我们称之为拖尾 lambda 表达式

val product = items.fold(1) { acc, e -> acc * e }

  在kotlin中,如果函数只有lambda表达式,则调用的时候,可以省略圆括号

val product = items.fold { acc, e -> acc * e }

  在kotlin中,如果lambda表达式只有一个参数,则可以使用it来代替该参数,并忽略->符号

    var lists = listOf("","s")
    lists.forEach { print(it) }
    /** 等价写法 **/
    lists.forEach { it -> print(it) }

  lambda表达式语法如下

    1. 无参数
    val/var 变量名 = { 操作的代码 }
    
    2. 有参数
    val/var 变量名 : (参数的类型,参数类型,...) -> 返回值类型 = {参数1,参数2... -> 操作参数的代码 }
    当表达式的返回值类型可以由系统自己推导出来,则可以简写为
    val/var 变量名 = { 参数1 : 类型,参数2 : 类型, ... -> 操作参数的代码 }
    
    3. lambda表达式作为函数中的参数
    fun say(a : Int, 参数名 : (参数1 : 类型,参数2 : 类型, ... ) -> 表达式返回类型){
        参数名()  调用该lambda表达式
    }

  lambda表达式实际用例:

package com.kotline.learning

    private fun say() {
        println("**say**")
    }

    private fun people(hello: () -> Unit) {
        hello()
    }

    private fun people(content: String, hello: () -> Unit) {
        println("**people**$content")
    }

    fun main (args: Array<String>): Unit{
        people{say()}
        people("content", { say() })
        people("content") { say() }
    }

第3行定义了一个函数say,没有参数,没有返回值/或者说返回值为Unit
第7行定义了一个函数people,其参数为hello,类型为一个lambda表达式
第8行表示调用/执行这个lambda表达式
第11行定义了一个函数people,其参数为content和hello,类型一个是字符串型,一个lambda表达式

综上内容,当我们调用函数people的时候,就可以写为

/** 调用第7行的people方法 **/
people({say()})
因为kotlin的提出原则,上面的代码可以简写为:
people(){say()}
也可以简写为
people{say()}

  现在我们返回到线程方法thread的第六个参数:block

 block: () -> Unit

他表示一个lambda表示式,无参且返回类型为Unit,调用函数的写法为:

 block()

所以在函数thread的函数体中,即第13行,run方法中会调用到block

  现在我们来看看如果通过thread方法来创建一个立即运行的线程

fun printJob() {
    println("**printJob**")
}

thread({
	printJob()
})
/**  可简写为: **/

thread{
  printJob()
}

  通过对象表达式创建一个线程

    Thread(object: Runnable{
        override fun run() {
        }
    }).start();
/** IDE会提示修改为lambda形式:**/
    Thread(Runnable {
        printJob() 
    }).start();

  继承Thread类,非匿名内部类的方式实现

    var kotlinThread : KotlinThread = KotlinThread();
    kotlinThread.start();

	class KotlinThread : Thread() {
    	override fun run() {
        	super.run()
        	println("KotlinThread 开始运行")
    	}
	}
<think>我们将创建一个简单的CPU压力测试程序,通过执行密集计算来使CPU负载升高。 主要思路:创建多个线程,每个线程进行密集的数学计算(例如计算素数),并持续一段时间。 我们将实现以下功能: 1. 启动压力测试:创建多个线程运行计算任务。 2. 停止压力测试:停止所有计算线程。 3. 显示当前CPU使用率(可选,需要读取系统文件,但普通应用可能无法读取,因此这里我们只做简单的进度或状态显示)。 注意:由于Android平台限制,普通应用无法直接获取实时CPU温度或使用率(需要root权限)。因此,我们的应用将主要关注于让CPU满载运行,并显示测试状态。 步骤: 1. 创建一个管理类,用于启动和停止压力测试。 2. 使用线程池管理多个计算线程。 3. 在UI上显示测试状态(如运行时间、是否运行中等)。 代码实现: 首先,在Android Studio中创建一个新的Activity,例如`CpuStressTestActivity`。 布局文件(activity_cpu_stress_test.xml): ```xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <Button android:id="@+id/btnStart" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="开始压力测试" /> <Button android:id="@+id/btnStop" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="停止压力测试" /> <TextView android:id="@+id/tvStatus" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="状态: 未运行" android:textSize="18sp" /> <TextView android:id="@+id/tvTime" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="运行时间: 0秒" android:textSize="18sp" /> </LinearLayout> ``` Activity代码(CpuStressTestActivity.kt: ```kotlin import android.os.Bundle import android.os.Handler import android.os.Looper import android.widget.Button import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger import kotlin.math.sqrt class CpuStressTestActivity : AppCompatActivity() { private lateinit var btnStart: Button private lateinit var btnStop: Button private lateinit var tvStatus: TextView private lateinit var tvTime: TextView private var isTesting = AtomicBoolean(false) private var elapsedTime = AtomicInteger(0) private val handler = Handler(Looper.getMainLooper()) private val threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) private val timeRunnable = object : Runnable { override fun run() { if (isTesting.get()) { elapsedTime.incrementAndGet() updateTimeUI() handler.postDelayed(this, 1000) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_cpu_stress_test) btnStart = findViewById(R.id.btnStart) btnStop = findViewById(R.id.btnStop) tvStatus = findViewById(R.id.tvStatus) tvTime = findViewById(R.id.tvTime) btnStart.setOnClickListener { startStressTest() } btnStop.setOnClickListener { stopStressTest() } } private fun startStressTest() { if (isTesting.get()) return isTesting.set(true) elapsedTime.set(0) updateStatusUI("状态: 运行中") updateTimeUI() // 启动计时器 handler.post(timeRunnable) // 根据CPU核心数创建线程 val cores = Runtime.getRuntime().availableProcessors() // 为了增加压力,我们为每个核心创建多个线程(例如2倍) for (i in 0 until cores * 2) { threadPool.execute { // 执行密集计算任务 while (isTesting.get()) { calculatePrimes(1000000) // 计算1000000以内的素数 } } } } private fun stopStressTest() { isTesting.set(false) updateStatusUI("状态: 已停止") handler.removeCallbacks(timeRunnable) } // 计算素数(密集计算任务) private fun calculatePrimes(n: Int): List<Int> { val primes = mutableListOf<Int>() for (i in 2..n) { if (isPrime(i)) { primes.add(i) } } return primes } private fun isPrime(n: Int): Boolean { if (n <= 1) return false if (n == 2) return true if (n % 2 == 0) return false val sqrtN = sqrt(n.toDouble()).toInt() var i = 3 while (i <= sqrtN) { if (n % i == 0) { return false } i += 2 } return true } private fun updateStatusUI(message: String) { runOnUiThread { tvStatus.text = message } } private fun updateTimeUI() { runOnUiThread { tvTime.text = "运行时间: ${elapsedTime.get()}秒" } } override fun onDestroy() { super.onDestroy() stopStressTest() threadPool.shutdownNow() } } ``` 说明: 1. 我们创建了一个固定大小的线程池,大小为处理器核心数的两倍(以充分压榨CPU)。 2. 每个线程执行一个循环,计算大范围内的素数(计算素数是一个CPU密集型操作)。 3. 使用`AtomicBoolean`控制测试的启停。 4. 使用一个计时器每秒钟更新一次运行时间。 注意: - 这个测试会使CPU满载,可能导致设备发热,请谨慎使用。 - 在测试过程中,用户界面可能变得卡顿,因为我们在主线程外使用了大量计算,但UI更新仍然在主线程,且CPU资源紧张。 优化点: - 可以增加进度条显示测试进度(但这里没有具体的进度,因为我们只是让CPU满载运行)。 - 可以添加温度监控(需要root权限或系统权限),但一般应用无法实现。 相关权限:这个应用不需要额外的权限,因为不涉及文件或网络操作。 §§相关问题§§: 1. 如何避免CPU压力测试导致设备过热自动关机? 2. 在Android中如何获取实时的CPU使用率? 3. 如何实现一个可调节强度的CPU压力测试? 4.Kotlin中,除了计算素数,还有哪些常用的CPU密集型算法? </think> 以下是一个使用 Kotlin 在 Android 平台上实现的 CPU 压力测试程序。该程序通过创建多个线程执行密集计算任务,使 CPU 达到高负载状态,并提供实时性能监控。 ### CPU 压力测试程序实现 ```kotlin import android.os.Bundle import android.os.Handler import android.os.Looper import android.widget.Button import android.widget.ProgressBar import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import java.math.BigInteger import kotlin.math.sqrt class CpuStressActivity : AppCompatActivity() { private lateinit var startButton: Button private lateinit var stopButton: Button private lateinit var progressBar: ProgressBar private lateinit var statusText: TextView private lateinit var timeText: TextView private lateinit var cpuUsageText: TextView private var stressJob: Job? = null private var monitorJob: Job? = null private var startTime = 0L private var elapsedTime = 0L private val handler = Handler(Looper.getMainLooper()) // 监控间隔(毫秒) private val monitorInterval = 1000L override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_cpu_stress) startButton = findViewById(R.id.btn_start) stopButton = findViewById(R.id.btn_stop) progressBar = findViewById(R.id.progress_bar) statusText = findViewById(R.id.tv_status) timeText = findViewById(R.id.tv_time) cpuUsageText = findViewById(R.id.tv_cpu_usage) startButton.setOnClickListener { startStressTest() } stopButton.setOnClickListener { stopStressTest() } // 初始化UI状态 updateUI(false) } private fun startStressTest() { if (stressJob?.isActive == true) return // 重置状态 startTime = System.currentTimeMillis() elapsedTime = 0 progressBar.progress = 0 updateUI(true) // 启动压力测试 stressJob = CoroutineScope(Dispatchers.Default).launch { val threads = mutableListOf<Thread>() val cores = Runtime.getRuntime().availableProcessors() // 为每个CPU核心创建2个压力线程 for (i in 0 until cores * 2) { val thread = Thread { while (!isInterrupted()) { performCpuIntensiveTask() } } thread.priority = Thread.MAX_PRIORITY thread.start() threads.add(thread) } // 等待测试完成或取消 while (isActive) { delay(100) } // 停止所有工作线程 threads.forEach { it.interrupt() } } // 启动性能监控 startPerformanceMonitoring() } private fun stopStressTest() { stressJob?.cancel() monitorJob?.cancel() updateUI(false) } // CPU密集型任务:计算大数阶乘和素数 private fun performCpuIntensiveTask() { // 计算大数阶乘 var factorial = BigInteger.ONE for (i in 1..1000) { factorial = factorial.multiply(BigInteger.valueOf(i.toLong())) } // 计算素数 for (num in 1_000_000..1_000_500) { isPrime(num) } } // 检查是否为素数 private fun isPrime(n: Int): Boolean { if (n <= 1) return false if (n == 2) return true if (n % 2 == 0) return false val sqrt = sqrt(n.toDouble()).toInt() for (i in 3..sqrt step 2) { if (n % i == 0) return false } return true } // 启动性能监控协程 private fun startPerformanceMonitoring() { monitorJob = CoroutineScope(Dispatchers.Main).launch { while (isActive) { // 更新运行时间 elapsedTime = System.currentTimeMillis() - startTime timeText.text = "运行时间: ${elapsedTime / 1000}秒" // 更新进度(每5秒增加1%) val progress = (elapsedTime / 5000).coerceAtMost(100L).toInt() progressBar.progress = progress // 模拟CPU使用率读数(实际实现需要系统权限) val fakeCpuUsage = 70 + (30 * Math.random()).toInt() cpuUsageText.text = "CPU负载: $fakeCpuUsage%" delay(monitorInterval) } } } // 更新UI状态 private fun updateUI(isRunning: Boolean) { startButton.isEnabled = !isRunning stopButton.isEnabled = isRunning statusText.text = if (isRunning) { "状态: 压力测试运行中" } else { "状态: 准备就绪" } } override fun onDestroy() { super.onDestroy() stopStressTest() } } ``` ### 布局文件 (res/layout/activity_cpu_stress.xml) ```xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp" android:gravity="center"> <TextView android:id="@+id/tv_status" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="状态: 准备就绪" android:textSize="18sp" android:layout_marginBottom="16dp"/> <ProgressBar android:id="@+id/progress_bar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:max="100" android:progress="0" android:layout_marginBottom="16dp"/> <TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="运行时间: 0秒" android:textSize="16sp" android:layout_marginBottom="8dp"/> <TextView android:id="@+id/tv_cpu_usage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="CPU负载: 0%" android:textSize="16sp" android:layout_marginBottom="24dp"/> <Button android:id="@+id/btn_start" android:layout_width="200dp" android:layout_height="wrap_content" android:text="开始测试" android:layout_marginBottom="16dp"/> <Button android:id="@+id/btn_stop" android:layout_width="200dp" android:layout_height="wrap_content" android:text="停止测试" android:enabled="false"/> </LinearLayout> ``` ### 代码功能详解 1. **CPU 压力测试核心逻辑**: - `performCpuIntensiveTask()` 方法执行两个 CPU 密集型操作: - 计算大数阶乘(使用 BigInteger 防止溢出) - 检查大范围数字是否为素数(使用数学优化) - 为每个 CPU 核心创建 2 个工作线程,最大化 CPU 利用率 2. **协程管理**: - 使用 Kotlin 协程处理异步任务 - `stressJob` 管理压力测试任务 - `monitorJob` 负责性能监控和 UI 更新 3. **性能监控**: - 实时显示测试运行时间 - 进度条显示测试进度(模拟) - CPU 负载显示(实际实现需要系统权限) 4. **UI 控制**: - 开始/停止按钮控制测试状态 - 状态文本显示当前测试状态 - 进度条直观展示测试进度 ### 实际 CPU 监控实现(需要系统权限) 实际获取 CPU 使用率需要读取系统文件,普通应用无法直接访问。以下是需要系统权限的实现方法: ```kotlin // 在 AndroidManifest.xml 中添加权限 // <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> private fun getCpuUsage(): Double { return try { val process = Runtime.getRuntime().exec("top -n 1") val reader = BufferedReader(InputStreamReader(process.inputStream)) var line: String? var cpuUsage = 0.0 while (reader.readLine().also { line = it } != null) { if (line?.contains("CPU:") == true) { val regex = Regex("(\\d+\\.\\d+)%") val match = regex.find(line!!) match?.groups?.get(1)?.value?.toDoubleOrNull()?.let { cpuUsage = it } break } } reader.close() cpuUsage } catch (e: Exception) { e.printStackTrace() 0.0 } } ``` ### 注意事项 1. **设备安全**: - 压力测试会导致 CPU 温度升高 - 建议测试时间不超过 5 分钟 - 设备可能触发过热保护自动降频 2. **权限要求**: - 实际 CPU 监控需要系统级权限 - 普通应用可显示模拟负载值 3. **性能影响**: - 测试时设备会变得卡顿 - 建议关闭其他后台应用 - 连接充电器防止电量耗尽
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值