├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── threadlib.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── codoon │ │ └── threaddemo │ │ ├── CommonUtil.kt │ │ ├── MainActivity.kt │ │ └── test │ │ ├── MyAsyncTask.kt │ │ ├── MyRunnable.kt │ │ └── MyThread.kt │ └── res │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── local.properties ├── repositories └── com │ └── codoon │ └── threadtracker │ ├── threadtracker-plugin │ ├── 1.1.0 │ │ ├── threadtracker-plugin-1.1.0.jar │ │ ├── threadtracker-plugin-1.1.0.jar.md5 │ │ ├── threadtracker-plugin-1.1.0.jar.sha1 │ │ ├── threadtracker-plugin-1.1.0.pom │ │ ├── threadtracker-plugin-1.1.0.pom.md5 │ │ └── threadtracker-plugin-1.1.0.pom.sha1 │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ └── maven-metadata.xml.sha1 │ └── threadtracker │ ├── 1.1.0 │ ├── threadtracker-1.1.0.aar │ ├── threadtracker-1.1.0.aar.md5 │ ├── threadtracker-1.1.0.aar.sha1 │ ├── threadtracker-1.1.0.pom │ ├── threadtracker-1.1.0.pom.md5 │ └── threadtracker-1.1.0.pom.sha1 │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ └── maven-metadata.xml.sha1 ├── settings.gradle ├── threadtracker-plugin ├── .gitignore ├── build.gradle └── src │ └── main │ ├── groovy │ └── com │ │ └── codoon │ │ └── threadtracker │ │ └── plugins │ │ ├── AddPackageMethodVisitor.java │ │ ├── ChangeProxyMethodVisitor.java │ │ ├── ChangeSuperMethodVisitor.java │ │ ├── ClassConstant.java │ │ ├── PluginUtils.java │ │ ├── ThreadTrackerClassVisitor.java │ │ └── ThreadTrackerTransform.groovy │ └── resources │ └── META-INF │ └── gradle-plugins │ └── com.codoon.threadtracker.properties └── threadtracker ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── java └── com │ └── codoon │ └── threadtracker │ ├── ThreadInfoManager.kt │ ├── ThreadTrackerInitializer.kt │ ├── TrackerUtils.kt │ ├── UserPackage.java │ ├── bean │ ├── ShowInfo.kt │ ├── ThreadInfo.kt │ ├── ThreadInfoResult.kt │ └── ThreadPoolInfo.kt │ ├── proxy │ ├── AsyncTaskHook.kt │ ├── PoolRunnableAndOther.kt │ ├── ProxyAsyncTaskExecutor.java │ ├── ProxyExecutorService.java │ ├── ProxyExecutors.kt │ ├── ProxyThreadPoolExecutor.kt │ ├── TBaseHandlerThread.kt │ ├── TBaseScheduledThreadPoolExecutor.kt │ ├── TBaseThread.kt │ ├── TBaseThreadFactory.kt │ ├── TBaseThreadPoolExecutor.kt │ └── TBaseTimer.kt │ └── ui │ ├── ThreadDetailsActivity.kt │ ├── TrackerActivity.kt │ └── TrackerAdapter.kt └── res ├── drawable ├── threadtracker_refresh_progress.xml └── threadtracker_refreshing.png ├── layout ├── threadtracker_activity_details.xml ├── threadtracker_activity_tracker.xml └── threadtracker_thread_item.xml ├── mipmap-xxhdpi ├── threadtracker_arrow_back.png ├── threadtracker_launcher.png ├── threadtracker_launcher_round.png └── threadtracker_refresh.png └── values ├── colors.xml ├── strings.xml └── styles.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /.gradle/4.10/ 3 | /.gradle/vcs-1/ 4 | /build/android-profile/ 5 | /gradlew 6 | /gradlew.bat 7 | /ThreadTracker.iml 8 | /.gradle/buildOutputCleanup/ 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ThreadTracker 2 | Android 线程追踪工具 3 | 4 | ## 开发背景 5 | 随着项目规模越来越大,线程数量暴涨问题很难避免。在 Android 中每个线程都在自己独立的栈中运行,我们虽可以用 Thread.getAllStackTraces() 获取到运行栈信息,但却无法得知线程被启动原因。当做性能优化打开 Profiler 工具时,可能瞬间映入眼帘几百个线程,甚至很多都是无名线程,以致于想去优化,都无从下手。 6 | 7 | ThreadTracker 致力于解决这样的问题;它可以方便的查看当前时刻线程**被启动堆栈**、线程池**被创建堆栈**、线程池中的某线程当前正在执行的**task添加栈**(对于线程池来说,其中线程被启动的堆栈并不重要,这取决于线程池策略,重要的是线程正在执行的任务是在哪里被添加的)、以及线程-线程池之间的树状关系图,并**自动高亮**堆栈中用户代码,让您一眼看出问题根源。 8 | 9 | ## 效果演示 10 | ![主界面](https://github.com/codoon/resource/blob/master/threadtracker/img/t1.jpg) 11 | ![详情](https://github.com/codoon/resource/blob/master/threadtracker/img/t2.jpg) 12 | 13 | 另外,当一个线程/线程池是被另一个子线程启动/创建,可以通过点击 show detail 追溯调用链,直到到达主线程为止。 14 | 15 | \* 注:如果您需要追踪 ASyncTask 相关信息,请在 Android 5.0 及以上手机运行,4.x 系统上对 ASyncTask 的 Hook 暂无法成功。 16 | 17 | ## 实现原理 18 | https://juejin.im/post/6855586076132655118/ 19 | 20 | ## 使用方式 21 | 22 | 首先需要 jcenter: 23 | 24 | repositories { 25 | jcenter() 26 | } 27 | 28 | 然后在您的 project gradle 的 dependencies 中添加: 29 | 30 | classpath "com.codoon.threadtracker:threadtracker-plugin:1.1.0" 31 | 32 | 在您的 application gradle 中添加: 33 | 34 | apply plugin: 'com.codoon.threadtracker' 35 | 36 | debugImplementation 'com.codoon.threadtracker:threadtracker:1.1.0' 37 | 38 | 打包后会多生成一个 TreadTracker 图标,打开即可使用。 39 | 40 | \* 如果您的项目尚不支持 androidx,可把以上 version 全部改成 1.0.0;版本 1.1.0 及以后均需 androidx 支持。 41 | 42 | ## Coming soon... 43 | * 统计三方 jar 包线程状态,看是谁在为所欲为 44 | * 按线程状态/类型筛选,按运行时间排序 45 | * 记录/恢复当前线程信息快照 46 | 47 | ## 协议 48 | Apache-2.0 license 49 | ThreadTracker 基于 Apache-2.0 协议进行分发和使用。 50 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /app.iml 3 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'com.codoon.threadtracker' 5 | 6 | android { 7 | compileSdkVersion 30 8 | buildToolsVersion "30.0.1" 9 | 10 | defaultConfig { 11 | applicationId "com.codoon.threaddemo" 12 | minSdkVersion 16 13 | targetSdkVersion 30 14 | versionCode 1 15 | versionName "1.0" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | } 26 | 27 | repositories { 28 | maven { 29 | url uri('../repositories') 30 | } 31 | } 32 | 33 | dependencies { 34 | implementation fileTree(dir: 'libs', include: ['*.jar']) 35 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 36 | implementation 'androidx.appcompat:appcompat:1.1.0' 37 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 38 | debugImplementation 'com.codoon.threadtracker:threadtracker:1.1.0' 39 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 40 | implementation 'io.reactivex.rxjava2:rxjava:2.2.19' 41 | } 42 | -------------------------------------------------------------------------------- /app/libs/threadlib.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codoon/ThreadTracker/9368e2a6ad7c4055116dcceb3d7c5bf575b7920e/app/libs/threadlib.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/codoon/threaddemo/CommonUtil.kt: -------------------------------------------------------------------------------- 1 | package com.codoon.threaddemo 2 | 3 | import android.util.Log 4 | 5 | object CommonUtil { 6 | fun printAllThread() { 7 | val threadMap = Thread.getAllStackTraces() 8 | Log.e("ThreadDebug", "all start==============================================") 9 | for ((thread, stackElements) in threadMap) { 10 | Log.e( 11 | "ThreadDebug", 12 | "name:${thread.name} id:${thread.id} priority:${thread.priority} state:${thread.state}" 13 | ) 14 | for (i in stackElements.indices) { 15 | val stringBuilder = StringBuilder(" ") 16 | stringBuilder.append(stackElements[i].className + ".") 17 | .append(stackElements[i].methodName + "(") 18 | .append(stackElements[i].fileName + ":") 19 | .append(stackElements[i].lineNumber.toString() + ")") 20 | Log.e("ThreadDebug", stringBuilder.toString()) 21 | } 22 | 23 | Log.e("ThreadDebug", "\n\n-") 24 | } 25 | Log.e("ThreadDebug", "all end==============================================") 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codoon/threaddemo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.codoon.threaddemo 2 | 3 | import android.os.AsyncTask 4 | import android.os.Bundle 5 | import android.os.Handler 6 | import android.os.HandlerThread 7 | import androidx.appcompat.app.AppCompatActivity 8 | import com.codoon.threaddemo.test.MyAsyncTask 9 | import com.codoon.threaddemo.test.MyRunnable 10 | import com.codoon.threaddemo.test.MyThread 11 | import com.codoon.threadlib.MyJar 12 | import io.reactivex.Observable 13 | import io.reactivex.schedulers.Schedulers 14 | import kotlinx.android.synthetic.main.activity_main.* 15 | import java.util.* 16 | import java.util.concurrent.* 17 | 18 | /** 19 | * 使用各种方式创建各种线程、线程池、以及线程中嵌套启动新线程,用来查看线程溯源的效果。 20 | */ 21 | class MainActivity : AppCompatActivity() { 22 | private val wait0 = Object() 23 | 24 | // rx线程 25 | private val observable = Observable.just("").map { 26 | Thread.sleep(5000) 27 | }.subscribeOn(Schedulers.io()) 28 | 29 | // 自定义线程池 30 | private val threadPool = MyThreadPool( 31 | 3, 32 | 3, 33 | 960, 34 | TimeUnit.SECONDS, 35 | LinkedBlockingQueue(2) 36 | ) 37 | 38 | override fun onCreate(savedInstanceState: Bundle?) { 39 | super.onCreate(savedInstanceState) 40 | 41 | setContentView(R.layout.activity_main) 42 | 43 | // 外层执行完后即销毁,里层查看调用栈时能查到外层threadId 44 | Thread { 45 | Thread { 46 | Thread.sleep(10000000) 47 | }.start() 48 | }.start() 49 | 50 | 51 | // 按钮触发的各种线程 52 | button.setOnClickListener { 53 | button.isEnabled = false 54 | 55 | // 多重嵌套 56 | observable.observeOn(Schedulers.computation()).subscribe { 57 | // 自定义线程 58 | val myThread = MyThread(Runnable { 59 | startDiffTimeThread() 60 | alwaysRunning() 61 | }) 62 | myThread.name = "MY 666 THREAD" 63 | myThread.start() 64 | 65 | Thread.sleep(500000000) 66 | } 67 | 68 | // threadPool以两种不同方式添加任务 69 | threadPool.execute(MyRunnable()) 70 | threadPool.submit(Callable { 71 | startAsync() 72 | synchronized(wait0) { 73 | wait0.wait() 74 | } 75 | "" 76 | }) 77 | } 78 | 79 | // 调用系统函数打印出当前所有线程以及运行中堆栈 80 | // rootLayout.postDelayed({ 81 | // CommonUtil.printAllThread() 82 | // }, 5000) 83 | } 84 | 85 | // 主要用来测试刷新功能 86 | private fun startDiffTimeThread() { 87 | for (i in 0..6) { 88 | Thread { 89 | Thread.sleep((i + 5) * 1000L) 90 | }.apply { 91 | name = "SLEEP-$i" 92 | start() 93 | } 94 | } 95 | } 96 | 97 | // 各种方式使用AsyncTask 98 | private fun startAsync() { 99 | 100 | AsyncTask.execute { 101 | Thread.sleep(30000) 102 | } 103 | AsyncTask.THREAD_POOL_EXECUTOR.execute { 104 | alwaysRunning() 105 | } 106 | val myAsyncTask1 = MyAsyncTask() 107 | myAsyncTask1.execute("1") 108 | val myAsyncTask2 = MyAsyncTask() 109 | myAsyncTask2.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, "2") 110 | val myAsyncTask3 = MyAsyncTask() 111 | myAsyncTask3.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "3") 112 | val myAsyncTask4 = MyAsyncTask() 113 | myAsyncTask4.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "4") 114 | val myAsyncTask5 = MyAsyncTask() 115 | myAsyncTask5.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "5") 116 | 117 | // 类型强转,不应引起crash 118 | val tf = (AsyncTask.THREAD_POOL_EXECUTOR as ThreadPoolExecutor).threadFactory 119 | } 120 | 121 | private fun alwaysRunning() { 122 | var i = 0 123 | while (true) { 124 | i++ 125 | i-- 126 | } 127 | } 128 | 129 | // 其他生命周期中启动线程 130 | 131 | override fun onResume() { 132 | super.onResume() 133 | 134 | val jarThread = MyJar() 135 | jarThread.startJarThread() 136 | } 137 | 138 | override fun onStart() { 139 | super.onStart() 140 | 141 | Thread { 142 | // 测试HandlerThread和Timer追踪情况 143 | val pool = Executors.newFixedThreadPool(5) 144 | pool.execute { 145 | val ht = HandlerThread("My HandlerThread") 146 | ht.start() 147 | val h = Handler(ht.looper) 148 | h.sendEmptyMessageDelayed(123, 3333333) 149 | Thread.sleep(10000000) 150 | } 151 | pool.execute { 152 | Thread.sleep(10000000) 153 | } 154 | pool.execute { 155 | val timer = Timer() 156 | timer.schedule(object : TimerTask() { 157 | override fun run() { 158 | 159 | } 160 | }, 0, 1000) 161 | Thread.sleep(10) 162 | } 163 | 164 | Thread.sleep(10000000) 165 | }.start() 166 | } 167 | 168 | override fun onDestroy() { 169 | super.onDestroy() 170 | System.exit(0) 171 | } 172 | 173 | 174 | // 自定义线程池 175 | private inner class MyThreadPool( 176 | corePoolSize: Int, 177 | maximumPoolSize: Int, 178 | keepAliveTime: Long, 179 | unit: TimeUnit?, 180 | workQueue: BlockingQueue? 181 | ) : ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue) { 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /app/src/main/java/com/codoon/threaddemo/test/MyAsyncTask.kt: -------------------------------------------------------------------------------- 1 | package com.codoon.threaddemo.test 2 | 3 | import android.os.AsyncTask 4 | 5 | class MyAsyncTask : AsyncTask() { 6 | override fun doInBackground(vararg params: String?): String? { 7 | synchronized(MyAsyncTask::class.java) { 8 | Thread.sleep(1000000) 9 | } 10 | return "" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/codoon/threaddemo/test/MyRunnable.kt: -------------------------------------------------------------------------------- 1 | package com.codoon.threaddemo.test 2 | 3 | class MyRunnable : Runnable { 4 | override fun run() { 5 | Thread.sleep(10000000) 6 | } 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codoon/threaddemo/test/MyThread.kt: -------------------------------------------------------------------------------- 1 | package com.codoon.threaddemo.test 2 | 3 | class MyThread(target: Runnable) : Thread(target) -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |