├── .gitignore ├── LICENSE.txt ├── README.md ├── ic_launcher.png ├── jars ├── lite-go-1.0.0.jar └── 更新记录Update-History.txt ├── library ├── AndroidManifest.xml ├── proguard-android-optimize.txt ├── project.properties └── src │ └── com │ └── litesuits │ └── go │ ├── OverloadPolicy.java │ ├── PriorityRunnable.java │ ├── SchedulePolicy.java │ ├── SmartExecutor.java │ └── utils │ └── GoUtil.java └── samples ├── AndroidManifest.xml ├── libs └── lite-go-1.0.0.jar ├── res ├── drawable-xhdpi │ └── ic_launcher.png ├── drawable │ └── selector_list_item.xml ├── layout │ ├── list_item.xml │ └── main.xml ├── values-zh │ └── strings.xml └── values │ ├── strings.xml │ └── styles.xml └── src └── com └── litesuits └── go └── sample └── MainActivity.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | .idea/ 5 | *.iml 6 | 7 | # Files for the Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 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 | # LiteGo:「迷你」的Android异步并发类库 2 | 3 | LiteGo是一款基于Java语言的「异步并发类库」,它的核心是一枚「迷你」并发器,它可以自由地设置同一时段的最大「并发」数量,等待「排队」线程数量,还可以设置「排队策略」和「超载策略」。 4 | LiteGo可以直接投入Runnable、Callable、FutureTask 等类型的实现来运行一个任务,它的核心组件是「SmartExecutor」,它可以用来作为「App」内支持异步并发的唯一组件。 5 | 在一个App中「SmartExecutor」可以有多个实例,每个实例都有完全的「独立性」,比如独立的「核心并发」、「排队等待」指标,独立的「运行调度和满载处理」策略,但所有实例「共享一个线程池」。 6 | 这种机制既满足不同模块对线程控制和任务调度的独立需求,又共享一个池资源来节省开销,最大程度上节约资源复用线程,帮助提升性能。 7 | 8 | --- 9 | 官网 : [litesuits.com](http://litesuits.com?f=litego) 10 | 11 | QQ群 : [42960650][1] 12 | 13 | --- 14 | 15 | ### LiteGo 背景 16 | 17 | 关于异步、并发的现状和问题 18 | 19 | - 线程的创建代价比较大,尤其在短时间需要大量并发的场景下问题突出,所以Java有了线程池来管理和复用线程。 20 | - 一般来讲,一个App一个线程池足矣!也不需要自己完全重新实现,充分利用Doug Lea(对java贡献最大的个人)主写的concurrent库。 21 | - 现在框架众多,有的独立精悍,也有集大成者,建议阅读源码,最好知根知底,很可能在他们有自己的线程池,这个时候如果你不注意管理线程那就雪上加霜咯。 22 | 23 | 所以,鉴于此我写了这个类库,来统一线程池,明确和控制管理策略。 24 | 25 | ### LiteGo 理念 26 | 27 | - 清闲时线程不要多持,最好不要超过CPU数量,根据具体应用类型和场景来决策。 28 | - 瞬间并发不要过多,最好保持在CPU数量左右,或者可以多几个问题并不大。 29 | - 注意控制排队和满载策略,大量并发瞬间起来的场景下也能轻松应对。 30 | 31 | 同时并发的线程数量不要过多,最好保持在CPU核数左右,过多了CPU时间片过多的轮转分配造成吞吐量降低,过少了不能充分利用CPU,并发数可以适当比CPU核数多一点没问题。 32 | 33 | 还有个小小的个人建议,业务上合理调度任务,优化业务逻辑,从自己做起,不胡搞乱搞咯。 34 | 35 | ### LiteGo 特性 36 | > 37 | 可定义核心并发线程数,即同一时间并发的请求数量。 38 | > 39 | 可定义等待排队线程数,即超出核心并发数后可排队请求数量。 40 | > 41 | 可定义等待队列进入执行状态的策略:先来先执行,后来先执行。 42 | > 43 | 可定义等待队列满载后处理新请求的策略: 44 | > 45 | - 抛弃队列中最新的任务 46 | - 抛弃队列中最旧的任务 47 | - 抛弃当前新任务 48 | - 直接执行(阻塞当前线程) 49 | - 抛出异常(中断当前线程) 50 | 51 | 52 | ### LiteGo 使用。 OK,LET IT GO! 53 | 54 | 初始化: 55 | 56 | ```java 57 | 58 | // 智能并发调度控制器:设置[最大并发数],和[等待队列]大小 59 | SmartExecutor smallExecutor = new SmartExecutor(); 60 | 61 | // set temporary parameter just for test 62 | // 一下参数设置仅用来测试,具体设置看实际情况。 63 | 64 | // number of concurrent threads at the same time, recommended core size is CPU count 65 | // 开发者均衡性能和业务场景,自己调整同一时段的最大并发数量 66 | smallExecutor.setCoreSize(2); 67 | 68 | // adjust maximum number of waiting queue size by yourself or based on phone performance 69 | // 开发者均衡性能和业务场景,自己调整最大排队线程数量 70 | smallExecutor.setQueueSize(2); 71 | 72 | // 任务数量超出[最大并发数]后,自动进入[等待队列],等待当前执行任务完成后按策略进入执行状态:后进先执行。 73 | smallExecutor.setSchedulePolicy(SchedulePolicy.LastInFirstRun); 74 | 75 | // 后续添加新任务数量超出[等待队列]大小时,执行过载策略:抛弃队列内最旧任务。 76 | smallExecutor.setOverloadPolicy(OverloadPolicy.DiscardOldTaskInQueue); 77 | ``` 78 | 79 | 上述代码设计了一个可同时并发「2」个线程,并发满载后等待队列可容纳「2」个线程排队,排队队列中后进的任务先执行,等待队列装满后新任务来到将抛弃队列中最老的任务。 80 | 81 | 测试多个线程并发的情况: 82 | 83 | ```java 84 | // 一次投入 4 个任务 85 | for (int i = 0; i < 4; i++) { 86 | final int j = i; 87 | smallExecutor.execute(new Runnable() { 88 | @Override 89 | public void run() { 90 | HttpLog.i(TAG, " TASK " + j + " is running now ----------->"); 91 | SystemClock.sleep(j * 200); 92 | } 93 | }); 94 | } 95 | 96 | // 再投入1个可能需要取消的任务 97 | Future future = smallExecutor.submit(new Runnable() { 98 | @Override 99 | public void run() { 100 | HttpLog.i(TAG, " TASK 4 will be canceled... ------------>"); 101 | SystemClock.sleep(1000); 102 | } 103 | }); 104 | 105 | // 合适的时机取消此任务 106 | future.cancel(false); 107 | ``` 108 | 109 | 上述代码,一次依次投入 0、1、2、3、4 五个任务,注意4任务是最后投入的,返回一个Future对象。 110 | 111 | 根据设置,0、1会立即执行,执行满载后2、3进入排队队列,排队满载后独立投入的任务4来到,队列中最老的任务2被移除,队列中为3、4 。 112 | 113 | 因为4随后被取消执行,所以最后输出: 114 | 115 | ```java 116 | TASK 0 is running now -----------> 117 | TASK 1 is running now -----------> 118 | TASK 3 is running now -----------> 119 | ``` 120 | 121 | 122 | ### LiteGO 基本原理 123 | 124 | 我们看 SmartExecutor 的几个主要方法: 125 | ```java 126 | public Future submit(Runnable task) 127 | 128 | public Future submit(Runnable task, T result) 129 | 130 | public Future submit(Callable task) 131 | 132 | public void submit(RunnableFuture task) 133 | 134 | public void execute(final Runnable command) 135 | ``` 136 | 137 | 最主要的是 execute 方法,其他几个方法是将任务封装为 FutureTask 投入到 execute 方法执行。因为 FutureTask 本质就是一个 RunnableFuture 对象,兼具 Runnable 和 Future 的特性和功能。 138 | 139 | 那么重点就是看 execute 方法了: 140 | ```java 141 | @Override 142 | public void execute(final Runnable command) { 143 | if (command == null) { 144 | return; 145 | } 146 | 147 | WrappedRunnable scheduler = new WrappedRunnable() { 148 | @Override 149 | public Runnable getRealRunnable() { 150 | return command; 151 | } 152 | 153 | public Runnable realRunnable; 154 | 155 | @Override 156 | public void run() { 157 | try { 158 | command.run(); 159 | } finally { 160 | scheduleNext(this); 161 | } 162 | } 163 | }; 164 | 165 | boolean callerRun = false; 166 | synchronized (lock) { 167 | if (runningList.size() < coreSize) { 168 | runningList.add(scheduler); 169 | threadPool.execute(scheduler); 170 | } else if (waitingList.size() < queueSize) { 171 | waitingList.addLast(scheduler); 172 | } else { 173 | switch (overloadPolicy) { 174 | case DiscardNewTaskInQueue: 175 | waitingList.pollLast(); 176 | waitingList.addLast(scheduler); 177 | break; 178 | case DiscardOldTaskInQueue: 179 | waitingList.pollFirst(); 180 | waitingList.addLast(scheduler); 181 | break; 182 | case CallerRuns: 183 | callerRun = true; 184 | break; 185 | case DiscardCurrentTask: 186 | break; 187 | case ThrowExecption: 188 | throw new RuntimeException("Task rejected from lite smart executor. " + command.toString()); 189 | default: 190 | break; 191 | } 192 | } 193 | //printThreadPoolInfo(); 194 | } 195 | if (callerRun) { 196 | command.run(); 197 | } 198 | } 199 | ``` 200 | 201 | 可以看到整个过程简单概括为: 202 | > 203 | 1. 把任务封装为一个类似“链表”的结构体,执行完一个,调度下一个。 204 | 2. 加锁防止并发时抢夺资源,判断当前运行任务数量。 205 | 3. 当前任务数少于并发最大数量则投入运行,若满载则投入等待队列尾部。 206 | 4. 若等待队列未满新任务进入排队,若满则执行满载处理策略。 207 | 5. 当一个任务执行完,其尾部通过“链接”的方式调度一个新任务执行。若没有任务,则结束。 208 | 209 | 其中「加锁」和将任务包装成「链表」是重点。 210 | 211 | 212 | [1]: http://shang.qq.com/wpa/qunwpa?idkey=19bf15b9c85ec15c62141dd00618f725e2983803cd2b48566fa0e94964ae8370 -------------------------------------------------------------------------------- /ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litesuits/android-lite-go/5a19d0ca6859ac7ca377c9aba98310a05eecb4b6/ic_launcher.png -------------------------------------------------------------------------------- /jars/lite-go-1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litesuits/android-lite-go/5a19d0ca6859ac7ca377c9aba98310a05eecb4b6/jars/lite-go-1.0.0.jar -------------------------------------------------------------------------------- /jars/更新记录Update-History.txt: -------------------------------------------------------------------------------- 1 | 更新记录Update-History 2 | 3 | 4 | 1.0.0 5 | > 6 | 可定义核心并发线程数,即同一时间并发的请求数量。 7 | > 8 | 可定义等待排队线程数,即超出核心并发数后可排队请求数量。 9 | > 10 | 可定义等待队列进入执行状态的策略:先来先执行,后来先执行。 11 | > 12 | 可定义等待队列满载后处理新请求的策略: 13 | > 14 | - 抛弃队列中最新的任务 15 | - 抛弃队列中最旧的任务 16 | - 抛弃当前新任务 17 | - 直接执行(阻塞当前线程) 18 | - 抛出异常(中断当前线程) -------------------------------------------------------------------------------- /library/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /library/proguard-android-optimize.txt: -------------------------------------------------------------------------------- 1 | # This is a configuration file for ProGuard. 2 | # http://proguard.sourceforge.net/index.html#manual/usage.html 3 | 4 | # Optimizations: If you don't want to optimize, use the 5 | # proguard-android.txt configuration file instead of this one, which 6 | # turns off the optimization flags. Adding optimization introduces 7 | # certain risks, since for example not all optimizations performed by 8 | # ProGuard works on all versions of Dalvik. The following flags turn 9 | # off various optimizations known to have issues, but the list may not 10 | # be complete or up to date. (The "arithmetic" optimization can be 11 | # used if you are only targeting Android 2.0 or later.) Make sure you 12 | # test thoroughly if you go this route. 13 | 14 | -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* 15 | -optimizationpasses 7 16 | -allowaccessmodification 17 | -dontpreverify 18 | 19 | # _________________________ 其实没啥混淆的,自己随意吧 _________________________ 20 | # The remainder of this file is identical to the non-optimized version 21 | # of the Proguard configuration file (except that the other file has 22 | # flags to turn off optimization). 23 | 24 | -dontusemixedcaseclassnames 25 | -dontskipnonpubliclibraryclasses 26 | -verbose 27 | 28 | # 使用注解 29 | -keepattributes *Annotation*,Signature,Exceptions 30 | 31 | # 保持混淆时类的实名及行号(--------------- 调试时打开 --------------) 32 | #-keepattributes SourceFile,LineNumberTable 33 | 34 | # 枚举须保住 see http://proguard.sourceforge.net/manual/examples.html#enumerations 35 | -keepclassmembers enum * { 36 | **[] $VALUES; 37 | public *; 38 | } -------------------------------------------------------------------------------- /library/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | android.library=true 16 | -------------------------------------------------------------------------------- /library/src/com/litesuits/go/OverloadPolicy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 litesuits.com 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.litesuits.go; 17 | 18 | 19 | /** 20 | * Policy of thread-pool-executor overload. 21 | * 22 | * @author MaTianyu 23 | * @date 2015-04-23 24 | */ 25 | public enum OverloadPolicy { 26 | DiscardNewTaskInQueue, 27 | DiscardOldTaskInQueue, 28 | DiscardCurrentTask, 29 | CallerRuns, 30 | ThrowExecption 31 | } 32 | -------------------------------------------------------------------------------- /library/src/com/litesuits/go/PriorityRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 litesuits.com 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.litesuits.go; 17 | 18 | /** 19 | * @author MaTianyu 20 | * @date 2015-04-23 21 | */ 22 | public abstract class PriorityRunnable implements Runnable { 23 | 24 | int priority; 25 | 26 | protected PriorityRunnable(int priority) { 27 | this.priority = priority; 28 | } 29 | 30 | public int getPriority() { 31 | return priority; 32 | } 33 | 34 | public void setPriority(int priority) { 35 | this.priority = priority; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /library/src/com/litesuits/go/SchedulePolicy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 litesuits.com 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.litesuits.go; 17 | 18 | /** 19 | * @author MaTianyu 20 | * @date 2015-04-23 21 | */ 22 | public enum SchedulePolicy { 23 | LastInFirstRun, 24 | FirstInFistRun 25 | } 26 | -------------------------------------------------------------------------------- /library/src/com/litesuits/go/SmartExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 litesuits.com 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.litesuits.go; 17 | 18 | import android.util.Log; 19 | import com.litesuits.go.utils.GoUtil; 20 | 21 | import java.util.LinkedList; 22 | import java.util.concurrent.*; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | 25 | /** 26 | * A smart thread pool executor, about {@link SmartExecutor}: 27 | * 28 | *
    29 | *
  • keep {@link #coreSize} tasks concurrent, and put them in {@link #runningList}, 30 | * maximum number of running-tasks at the same time is {@link #coreSize}.
  • 31 | *
  • when {@link #runningList} is full, put new task in {@link #waitingList} waiting for execution, 32 | * maximum of waiting-tasks number is {@link #queueSize}.
  • 33 | *
  • when {@link #waitingList} is full, new task is performed by {@link OverloadPolicy}.
  • 34 | *
  • when running task is completed, take it out from {@link #runningList}.
  • 35 | *
  • schedule next by {@link SchedulePolicy}, take next task out from {@link #waitingList} to execute, 36 | * and so on until {@link #waitingList} is empty.
  • 37 | * 38 | *
39 | * 40 | * @author MaTianyu 41 | * @date 2015-04-23 42 | */ 43 | public class SmartExecutor implements Executor { 44 | private static final String TAG = SmartExecutor.class.getSimpleName(); 45 | /** 46 | * debug mode turn 47 | */ 48 | private boolean debug = false; 49 | 50 | private static final int CPU_CORE = GoUtil.getCoresNumbers(); 51 | private static final int DEFAULT_CACHE_SENCOND = 5; 52 | private static ThreadPoolExecutor threadPool; 53 | private int coreSize = CPU_CORE; 54 | private int queueSize = coreSize * 32; 55 | private final Object lock = new Object(); 56 | private LinkedList runningList = new LinkedList(); 57 | private LinkedList waitingList = new LinkedList(); 58 | private SchedulePolicy schedulePolicy = SchedulePolicy.FirstInFistRun; 59 | private OverloadPolicy overloadPolicy = OverloadPolicy.DiscardOldTaskInQueue; 60 | 61 | 62 | public SmartExecutor() { 63 | initThreadPool(); 64 | } 65 | 66 | public SmartExecutor(int coreSize, int queueSize) { 67 | this.coreSize = coreSize; 68 | this.queueSize = queueSize; 69 | initThreadPool(); 70 | } 71 | 72 | protected synchronized void initThreadPool() { 73 | if (debug) { 74 | Log.v(TAG, "SmartExecutor core-queue size: " + coreSize + " - " + queueSize 75 | + " running-wait task: " + runningList.size() + " - " + waitingList.size()); 76 | } 77 | if (threadPool == null) { 78 | threadPool = createDefaultThreadPool(); 79 | } 80 | } 81 | 82 | public static ThreadPoolExecutor createDefaultThreadPool() { 83 | // 控制最多4个keep在pool中 84 | int corePoolSize = Math.min(4, CPU_CORE); 85 | return new ThreadPoolExecutor( 86 | corePoolSize, 87 | Integer.MAX_VALUE, 88 | DEFAULT_CACHE_SENCOND, TimeUnit.SECONDS, 89 | new SynchronousQueue(), 90 | new ThreadFactory() { 91 | static final String NAME = "lite-"; 92 | AtomicInteger IDS = new AtomicInteger(1); 93 | 94 | @Override 95 | public Thread newThread(Runnable r) { 96 | return new Thread(r, NAME + IDS.getAndIncrement()); 97 | } 98 | }, 99 | new ThreadPoolExecutor.DiscardPolicy()); 100 | } 101 | 102 | /** 103 | * turn on or turn off debug mode 104 | */ 105 | public void setDebug(boolean debug) { 106 | this.debug = debug; 107 | } 108 | 109 | public boolean isDebug() { 110 | return debug; 111 | } 112 | 113 | public static void setThreadPool(ThreadPoolExecutor threadPool) { 114 | SmartExecutor.threadPool = threadPool; 115 | } 116 | 117 | public static ThreadPoolExecutor getThreadPool() { 118 | return threadPool; 119 | } 120 | 121 | public boolean cancelWaitingTask(Runnable command) { 122 | boolean removed = false; 123 | synchronized (lock) { 124 | int size = waitingList.size(); 125 | if (size > 0) { 126 | for (int i = size - 1; i >= 0; i--) { 127 | if (waitingList.get(i).getRealRunnable() == command) { 128 | waitingList.remove(i); 129 | removed = true; 130 | } 131 | } 132 | } 133 | } 134 | return removed; 135 | } 136 | 137 | interface WrappedRunnable extends Runnable { 138 | Runnable getRealRunnable(); 139 | } 140 | 141 | protected RunnableFuture newTaskFor(Runnable runnable, T value) { 142 | return new FutureTask(runnable, value); 143 | } 144 | 145 | protected RunnableFuture newTaskFor(Callable callable) { 146 | return new FutureTask(callable); 147 | } 148 | 149 | /** 150 | * submit runnable 151 | */ 152 | public Future submit(Runnable task) { 153 | RunnableFuture ftask = newTaskFor(task, null); 154 | execute(ftask); 155 | return ftask; 156 | } 157 | 158 | /** 159 | * Creates a {@code FutureTask} that will, upon running, execute the 160 | * given {@code Runnable}, and arrange that {@code get} will return the 161 | * given result on successful completion. 162 | * 163 | * @param task the runnable task 164 | * @param result the result to return on successful completion. If 165 | * you don't need a particular result, consider using 166 | * constructions of the form: 167 | * {@code Future f = new FutureTask(runnable, null)} 168 | * @throws NullPointerException if the runnable is null 169 | */ 170 | public Future submit(Runnable task, T result) { 171 | RunnableFuture ftask = newTaskFor(task, result); 172 | execute(ftask); 173 | return ftask; 174 | } 175 | 176 | /** 177 | * submit callable 178 | */ 179 | public Future submit(Callable task) { 180 | RunnableFuture ftask = newTaskFor(task); 181 | execute(ftask); 182 | return ftask; 183 | } 184 | 185 | 186 | /** 187 | * submit RunnableFuture task 188 | */ 189 | public void submit(RunnableFuture task) { 190 | execute(task); 191 | } 192 | 193 | 194 | /** 195 | * When {@link #execute(Runnable)} is called, {@link SmartExecutor} perform actions: 196 | *
    197 | *
  1. if fewer than {@link #coreSize} tasks are running, post new task in {@link #runningList} and execute it immediately.
  2. 198 | *
  3. if more than {@link #coreSize} tasks are running, and fewer than {@link #queueSize} tasks are waiting, put task in {@link #waitingList}.
  4. 199 | *
  5. if more than {@link #queueSize} tasks are waiting ,schedule new task by {@link OverloadPolicy}
  6. 200 | *
  7. if running task is completed, schedule next task by {@link SchedulePolicy} until {@link #waitingList} is empty.
  8. 201 | *
202 | */ 203 | @Override 204 | public void execute(final Runnable command) { 205 | if (command == null) { 206 | return; 207 | } 208 | 209 | WrappedRunnable scheduler = new WrappedRunnable() { 210 | @Override 211 | public Runnable getRealRunnable() { 212 | return command; 213 | } 214 | 215 | @Override 216 | public void run() { 217 | try { 218 | command.run(); 219 | } finally { 220 | scheduleNext(this); 221 | } 222 | } 223 | }; 224 | 225 | boolean callerRun = false; 226 | synchronized (lock) { 227 | //if (debug) { 228 | // Log.v(TAG, "SmartExecutor core-queue size: " + coreSize + " - " + queueSize 229 | // + " running-wait task: " + runningList.size() + " - " + waitingList.size()); 230 | //} 231 | if (runningList.size() < coreSize) { 232 | runningList.add(scheduler); 233 | threadPool.execute(scheduler); 234 | //Log.v(TAG, "SmartExecutor task execute"); 235 | } else if (waitingList.size() < queueSize) { 236 | waitingList.addLast(scheduler); 237 | //Log.v(TAG, "SmartExecutor task waiting"); 238 | } else { 239 | //if (debug) { 240 | // Log.w(TAG, "SmartExecutor overload , policy is: " + overloadPolicy); 241 | //} 242 | switch (overloadPolicy) { 243 | case DiscardNewTaskInQueue: 244 | waitingList.pollLast(); 245 | waitingList.addLast(scheduler); 246 | break; 247 | case DiscardOldTaskInQueue: 248 | waitingList.pollFirst(); 249 | waitingList.addLast(scheduler); 250 | break; 251 | case CallerRuns: 252 | callerRun = true; 253 | break; 254 | case DiscardCurrentTask: 255 | break; 256 | case ThrowExecption: 257 | throw new RuntimeException("Task rejected from lite smart executor. " + command.toString()); 258 | default: 259 | break; 260 | } 261 | } 262 | //printThreadPoolInfo(); 263 | } 264 | if (callerRun) { 265 | if (debug) { 266 | Log.i(TAG, "SmartExecutor task running in caller thread"); 267 | } 268 | command.run(); 269 | } 270 | } 271 | 272 | private void scheduleNext(WrappedRunnable scheduler) { 273 | synchronized (lock) { 274 | boolean suc = runningList.remove(scheduler); 275 | //if (debug) { 276 | // Log.v(TAG, "Thread " + Thread.currentThread().getName() 277 | // + " is completed. remove prior: " + suc + ", try schedule next.."); 278 | //} 279 | if (!suc) { 280 | runningList.clear(); 281 | Log.e(TAG, 282 | "SmartExecutor scheduler remove failed, so clear all(running list) to avoid unpreditable error : " + scheduler); 283 | } 284 | if (waitingList.size() > 0) { 285 | WrappedRunnable waitingRun; 286 | switch (schedulePolicy) { 287 | case LastInFirstRun: 288 | waitingRun = waitingList.pollLast(); 289 | break; 290 | case FirstInFistRun: 291 | waitingRun = waitingList.pollFirst(); 292 | break; 293 | default: 294 | waitingRun = waitingList.pollLast(); 295 | break; 296 | } 297 | if (waitingRun != null) { 298 | runningList.add(waitingRun); 299 | threadPool.execute(waitingRun); 300 | Log.v(TAG, "Thread " + Thread.currentThread().getName() + " execute next task.."); 301 | } else { 302 | Log.e(TAG, 303 | "SmartExecutor get a NULL task from waiting queue: " + Thread.currentThread().getName()); 304 | } 305 | } else { 306 | if (debug) { 307 | Log.v(TAG, "SmartExecutor: all tasks is completed. current thread: " + 308 | Thread.currentThread().getName()); 309 | //printThreadPoolInfo(); 310 | } 311 | } 312 | } 313 | } 314 | 315 | public void printThreadPoolInfo() { 316 | if (debug) { 317 | Log.i(TAG, "___________________________"); 318 | Log.i(TAG, "state (shutdown - terminating - terminated): " + threadPool.isShutdown() 319 | + " - " + threadPool.isTerminating() + " - " + threadPool.isTerminated()); 320 | Log.i(TAG, "pool size (core - max): " + threadPool.getCorePoolSize() 321 | + " - " + threadPool.getMaximumPoolSize()); 322 | Log.i(TAG, "task (active - complete - total): " + threadPool.getActiveCount() 323 | + " - " + threadPool.getCompletedTaskCount() + " - " + threadPool.getTaskCount()); 324 | Log 325 | .i(TAG, "waitingList size : " + threadPool.getQueue().size() + " , " + threadPool.getQueue()); 326 | } 327 | } 328 | 329 | public int getCoreSize() { 330 | return coreSize; 331 | } 332 | 333 | public int getRunningSize() { 334 | return runningList.size(); 335 | } 336 | 337 | public int getWaitingSize() { 338 | return waitingList.size(); 339 | } 340 | 341 | /** 342 | * Set maximum number of concurrent tasks at the same time. 343 | * Recommended core size is CPU count. 344 | * 345 | * @param coreSize number of concurrent tasks at the same time 346 | * @return this 347 | */ 348 | public SmartExecutor setCoreSize(int coreSize) { 349 | if (coreSize <= 0) { 350 | throw new NullPointerException("coreSize can not <= 0 !"); 351 | } 352 | this.coreSize = coreSize; 353 | if (debug) { 354 | Log.v(TAG, "SmartExecutor core-queue size: " + coreSize + " - " + queueSize 355 | + " running-wait task: " + runningList.size() + " - " + waitingList.size()); 356 | } 357 | return this; 358 | } 359 | 360 | public int getQueueSize() { 361 | return queueSize; 362 | } 363 | 364 | /** 365 | * Adjust maximum number of waiting queue size by yourself or based on phone performance. 366 | * For example: CPU count * 32; 367 | * 368 | * @param queueSize waiting queue size 369 | * @return this 370 | */ 371 | public SmartExecutor setQueueSize(int queueSize) { 372 | if (queueSize < 0) { 373 | throw new NullPointerException("queueSize can not < 0 !"); 374 | } 375 | 376 | this.queueSize = queueSize; 377 | if (debug) { 378 | Log.v(TAG, "SmartExecutor core-queue size: " + coreSize + " - " + queueSize 379 | + " running-wait task: " + runningList.size() + " - " + waitingList.size()); 380 | } 381 | return this; 382 | } 383 | 384 | 385 | public OverloadPolicy getOverloadPolicy() { 386 | return overloadPolicy; 387 | } 388 | 389 | public void setOverloadPolicy(OverloadPolicy overloadPolicy) { 390 | if (overloadPolicy == null) { 391 | throw new NullPointerException("OverloadPolicy can not be null !"); 392 | } 393 | this.overloadPolicy = overloadPolicy; 394 | } 395 | 396 | public SchedulePolicy getSchedulePolicy() { 397 | return schedulePolicy; 398 | } 399 | 400 | public void setSchedulePolicy(SchedulePolicy schedulePolicy) { 401 | if (schedulePolicy == null) { 402 | throw new NullPointerException("SchedulePolicy can not be null !"); 403 | } 404 | this.schedulePolicy = schedulePolicy; 405 | } 406 | 407 | } 408 | -------------------------------------------------------------------------------- /library/src/com/litesuits/go/utils/GoUtil.java: -------------------------------------------------------------------------------- 1 | package com.litesuits.go.utils; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.content.Context; 6 | import android.content.DialogInterface; 7 | import android.util.Log; 8 | 9 | import java.io.File; 10 | import java.io.FileFilter; 11 | import java.text.SimpleDateFormat; 12 | import java.util.Date; 13 | import java.util.regex.Pattern; 14 | 15 | /** 16 | * @author MaTianyu 17 | * @date 2015-04-21 18 | */ 19 | public class GoUtil { 20 | private static final String TAG = GoUtil.class.getSimpleName(); 21 | 22 | private static final String PATH_CPU = "/sys/devices/system/cpu/"; 23 | private static final String CPU_FILTER = "cpu[0-9]+"; 24 | private static int CPU_CORES = 0; 25 | 26 | public static String formatDate(long millis) { 27 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 28 | return format.format(new Date(millis)); 29 | } 30 | 31 | /** 32 | * Get available processors. 33 | */ 34 | public static int getProcessorsCount() { 35 | return Runtime.getRuntime().availableProcessors(); 36 | } 37 | 38 | /** 39 | * Gets the number of cores available in this device, across all processors. 40 | * Requires: Ability to peruse the filesystem at "/sys/devices/system/cpu" 41 | * 42 | * @return The number of cores, or available processors if failed to get result 43 | */ 44 | public static int getCoresNumbers() { 45 | if (CPU_CORES > 0) { 46 | return CPU_CORES; 47 | } 48 | //Private Class to display only CPU devices in the directory listing 49 | class CpuFilter implements FileFilter { 50 | @Override 51 | public boolean accept(File pathname) { 52 | //Check if filename is "cpu", followed by a single digit number 53 | if (Pattern.matches(CPU_FILTER, pathname.getName())) { 54 | return true; 55 | } 56 | return false; 57 | } 58 | } 59 | try { 60 | //Get directory containing CPU info 61 | File dir = new File(PATH_CPU); 62 | //Filter to only list the devices we care about 63 | File[] files = dir.listFiles(new CpuFilter()); 64 | //Return the number of cores (virtual CPU devices) 65 | CPU_CORES = files.length; 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | if (CPU_CORES < 1) { 70 | CPU_CORES = Runtime.getRuntime().availableProcessors(); 71 | } 72 | if (CPU_CORES < 1) { 73 | CPU_CORES = 1; 74 | } 75 | Log.i(TAG, "CPU cores: " + CPU_CORES); 76 | return CPU_CORES; 77 | } 78 | 79 | public static AlertDialog.Builder dialogBuilder(Context context, String title, String msg) { 80 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 81 | if (msg != null) { 82 | builder.setMessage(msg); 83 | } 84 | if (title != null) { 85 | builder.setTitle(title); 86 | } 87 | return builder; 88 | } 89 | 90 | 91 | public static Dialog showTips(Context context, String title, String des) { 92 | return showTips(context, title, des, null, null); 93 | } 94 | 95 | public static Dialog showTips(Context context, String title, String des, String btn, 96 | DialogInterface.OnDismissListener dismissListener) { 97 | AlertDialog.Builder builder = dialogBuilder(context, title, des); 98 | builder.setCancelable(true); 99 | builder.setPositiveButton(btn, null); 100 | Dialog dialog = builder.show(); 101 | dialog.setCanceledOnTouchOutside(true); 102 | dialog.setOnDismissListener(dismissListener); 103 | return dialog; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /samples/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/libs/lite-go-1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litesuits/android-lite-go/5a19d0ca6859ac7ca377c9aba98310a05eecb4b6/samples/libs/lite-go-1.0.0.jar -------------------------------------------------------------------------------- /samples/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litesuits/android-lite-go/5a19d0ca6859ac7ca377c9aba98310a05eecb4b6/samples/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/res/drawable/selector_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /samples/res/layout/list_item.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /samples/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 23 | 24 | 25 | 33 | 34 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /samples/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LiteGo 5 | Lite Lib : LiteGo 6 | see more via code and log. 7 | 8 | 0. 投入 Runnable 9 | 1. 投入 FutureTask 10 | 2. 投入 Callable 11 | 3. 策略测试和取消任务 12 | 13 | 14 | -------------------------------------------------------------------------------- /samples/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | LiteGo 4 | Lite Lib : LiteGo 5 | see more via code and log. 6 | 7 | 0. Submit Runnable 8 | 1. Submit FutureTask 9 | 2. Submit Callable 10 | 3. Strategy Test 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 11 | 12 | 13 | 18 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /samples/src/com/litesuits/go/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.litesuits.go.sample; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.os.SystemClock; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.view.Window; 9 | import android.widget.AdapterView; 10 | import android.widget.ArrayAdapter; 11 | import android.widget.BaseAdapter; 12 | import android.widget.ListView; 13 | import com.litesuits.go.OverloadPolicy; 14 | import com.litesuits.go.SchedulePolicy; 15 | import com.litesuits.go.SmartExecutor; 16 | 17 | import java.util.concurrent.Callable; 18 | import java.util.concurrent.Future; 19 | import java.util.concurrent.FutureTask; 20 | 21 | public class MainActivity extends Activity { 22 | protected String TAG = MainActivity.class.getSimpleName(); 23 | protected ListView mListview; 24 | protected BaseAdapter mAdapter; 25 | protected Activity activity = null; 26 | 27 | protected SmartExecutor mainExecutor; 28 | 29 | /** 30 | * Called when the activity is first created. 31 | */ 32 | @Override 33 | public void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | requestWindowFeature(Window.FEATURE_NO_TITLE); 36 | setContentView(R.layout.main); 37 | activity = this; 38 | initViews(); 39 | initSmartExecutor(); 40 | 41 | } 42 | 43 | private void initViews() { 44 | mListview = (ListView) findViewById(R.id.listview); 45 | mAdapter = new ArrayAdapter(this, R.layout.list_item, R.id.tv_item, 46 | getResources().getStringArray(R.array.test_case_list)); 47 | mListview.setAdapter(mAdapter); 48 | mListview.setOnItemClickListener(new AdapterView.OnItemClickListener() { 49 | @Override 50 | public void onItemClick(AdapterView parent, View view, int position, long id) { 51 | clickTestItem(position); 52 | } 53 | }); 54 | } 55 | 56 | private void initSmartExecutor() { 57 | if (mainExecutor == null) { 58 | // set this temporary parameter, just for test 59 | // 智能并发调度控制器:设置[最大并发数],和[等待队列]大小仅供测试,具体根据实际场景设置。 60 | mainExecutor = new SmartExecutor(); 61 | 62 | // 打开调试和日志,发布时建议关闭。 63 | mainExecutor.setDebug(true); 64 | 65 | // number of concurrent threads at the same time, recommended core size is CPU count 66 | mainExecutor.setCoreSize(2); 67 | 68 | // adjust maximum number of waiting queue size by yourself or based on phone performance 69 | mainExecutor.setQueueSize(100); 70 | 71 | // 任务数量超出[最大并发数]后,自动进入[等待队列],等待当前执行任务完成后按策略进入执行状态:后进先执行。 72 | mainExecutor.setSchedulePolicy(SchedulePolicy.LastInFirstRun); 73 | 74 | // 后续添加新任务数量超出[等待队列]大小时,执行过载策略:抛弃队列内最旧任务。 75 | mainExecutor.setOverloadPolicy(OverloadPolicy.DiscardOldTaskInQueue); 76 | 77 | //GoUtil.showTips(activity, "LiteGo", "Let It Go!"); 78 | } 79 | } 80 | 81 | /** 82 | * 0. Submit Runnable 83 | * 1. Submit FutureTask 84 | * 2. Submit Callable 85 | * 3. Strategy Test 86 | */ 87 | private void clickTestItem(final int which) { 88 | switch (which) { 89 | case 0: 90 | // 0. Submit Runnable 91 | mainExecutor.submit(new Runnable() { 92 | @Override 93 | public void run() { 94 | Log.i(TAG, " Runnable start! thread id: " + Thread.currentThread().getId()); 95 | try { 96 | Thread.sleep(2000); 97 | } catch (InterruptedException e) { 98 | e.printStackTrace(); 99 | } 100 | Log.i(TAG, " Runnable end! thread id: " + Thread.currentThread().getId()); 101 | } 102 | }); 103 | break; 104 | 105 | case 1: 106 | // 1. Submit FutureTask 107 | FutureTask futureTask = new FutureTask(new Callable() { 108 | @Override 109 | public String call() throws Exception { 110 | Log.i(TAG, " FutureTask thread id: " + Thread.currentThread().getId()); 111 | return "FutureTask"; 112 | } 113 | }); 114 | mainExecutor.submit(futureTask); 115 | break; 116 | 117 | case 2: 118 | // 2. Submit Callable 119 | mainExecutor.submit(new Callable() { 120 | @Override 121 | public String call() throws Exception { 122 | Log.i(TAG, " Callable thread id: " + Thread.currentThread().getId()); 123 | return "Callable"; 124 | } 125 | }); 126 | 127 | break; 128 | 129 | case 3: 130 | // 3. Strategy Test 131 | 132 | // set this temporary parameter, just for test 133 | SmartExecutor smallExecutor = new SmartExecutor(); 134 | 135 | 136 | // number of concurrent threads at the same time, recommended core size is CPU count 137 | smallExecutor.setCoreSize(2); 138 | 139 | // adjust maximum number of waiting queue size by yourself or based on phone performance 140 | smallExecutor.setQueueSize(2); 141 | 142 | // 任务数量超出[最大并发数]后,自动进入[等待队列],等待当前执行任务完成后按策略进入执行状态:后进先执行。 143 | smallExecutor.setSchedulePolicy(SchedulePolicy.LastInFirstRun); 144 | 145 | // 后续添加新任务数量超出[等待队列]大小时,执行过载策略:抛弃队列内最旧任务。 146 | smallExecutor.setOverloadPolicy(OverloadPolicy.DiscardOldTaskInQueue); 147 | 148 | // 一次投入 4 个任务 149 | for (int i = 0; i < 4; i++) { 150 | final int j = i; 151 | smallExecutor.execute(new Runnable() { 152 | @Override 153 | public void run() { 154 | Log.i(TAG, " TASK " + j + " is running now ----------->"); 155 | SystemClock.sleep(j * 200); 156 | } 157 | }); 158 | } 159 | 160 | // 再投入1个需要取消的任务 161 | Future future = smallExecutor.submit(new Runnable() { 162 | @Override 163 | public void run() { 164 | Log.i(TAG, " TASK 4 will be canceled ... ------------>"); 165 | SystemClock.sleep(1000); 166 | } 167 | }); 168 | future.cancel(false); 169 | break; 170 | } 171 | } 172 | 173 | 174 | } 175 | --------------------------------------------------------------------------------