1.线程池的引入
  引入的好处:
  1)提升性能。创建和消耗对象费时费CPU资源
  2)防止内存过度消耗。控制活动线程的数量,防止并发线程过多。
  使用条件:
     假设在一台服务器完成一项任务的时间为T
     T1 创建线程的时间    
     T2 在线程中执行任务的时间,包括线程间同步所需时间    
     T3 线程销毁的时间     
     显然T = T1+T2+T3。注意这是一个极度简化的假设。
     可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。
     线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
     线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。

在Android中当同时并发多个网络线程时,引入线程池技术会极大地提高APP的性能。

2.线程池例子
 1)JDK自身带有线程池的实现类ThreadPoolExecutor
 2)下面是一个模拟ThreadPoolExecutor的例子,以加深对原理的理解

  1. public final class ThreadPool {
  2. // 线程池中默认线程的个数为5
  3. private static int worker_num = 5;
  4. // 工作线程
  5. private WorkThread[] workThreads;
  6.  
  7. // 任务队列,作为一个缓冲,List线程不安全
  8. private List<Runnable> taskQueue = new LinkedList<Runnable>();
  9.  
  10. private static ThreadPool threadPool;
  11.  
  12. // 创建具有默认线程个数的线程池
  13. private ThreadPool() {
  14. this(5);
  15. }
  16.  
  17. // 创建线程池,worker_num为线程池中工作线程的个数
  18. private ThreadPool(int worker_num) {
  19. ThreadPool.worker_num = worker_num;
  20. workThreads = new WorkThread[worker_num];
  21. for (int i = 0; i < worker_num; i++) {
  22. workThreads[i] = new WorkThread();
  23. workThreads[i].start();// 开启线程池中的线程
  24. }
  25. }
  26.  
  27. // 单态模式,获得一个默认线程个数的线程池
  28. public static ThreadPool getThreadPool() {
  29. return getThreadPool(ThreadPool.worker_num);
  30. }
  31.  
  32. // 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数
  33. // worker_num<=0创建默认的工作线程个数
  34. public static ThreadPool getThreadPool(int worker_num1) {
  35. if (threadPool == null)
  36. threadPool = new ThreadPool(worker_num1);
  37. return threadPool;
  38. }
  39.  
  40. // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
  41. public void addTask(Runnable task) {
  42. synchronized (taskQueue) {
  43. taskQueue.add(task);
  44. taskQueue. notifyAll();
  45. }
  46. }
  47.  
  48. // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
  49. public void destroy() {
  50. while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧
  51. try {
  52. Thread.sleep(10);
  53. } catch (InterruptedException e) {
  54. e.printStackTrace();
  55. }
  56. }
  57. // 工作线程停止工作,且置为null
  58. for (int i = 0; i < worker_num; i++) {
  59. workThreads[i].stopWorker();
  60. workThreads[i] = null;
  61. }
  62. threadPool=null;
  63. taskQueue.clear();// 清空任务队列
  64. }
  65.  
  66. /**
  67. * 内部类,工作线程
  68. */
  69. private class WorkThread extends Thread {
  70. // 该工作线程是否有效,用于结束该工作线程
  71. private boolean isRunning = true;
  72.  
  73. /*
  74. * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待
  75. */
  76. @Override
  77. public void run() {
  78. Runnable r = null;
  79. while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了
  80. synchronized (taskQueue) {
  81. while (isRunning && taskQueue.isEmpty()) {// 队列为空
  82. try {
  83. taskQueue.wait(20);
  84. } catch (InterruptedException e) {
  85. e.printStackTrace();
  86. }
  87. }
  88. if (!taskQueue.isEmpty())
  89. r = taskQueue.remove(0);// 取出任务
  90. }
  91. if (r != null) {
  92. r.run();// 执行任务
  93. }
  94. r = null;
  95. }
  96. }
  97.  
  98. // 停止工作,让该线程自然执行完run方法,自然结束
  99. public void stopWorker() {
  100. isRunning = false;
  101. }
  102. }
  103. }

Android之线程池深度剖析的更多相关文章

  1. Java之线程池深度剖析

    1.线程池的引入   引入的好处:   1)提升性能.创建和消耗对象费时费CPU资源   2)防止内存过度消耗.控制活动线程的数量,防止并发线程过多.   使用条件:      假设在一台服务器完成一 ...

  2. Java字节码常量池深度剖析与字节码整体结构分解

    常量池深度剖析: 在上一次[https://www.cnblogs.com/webor2006/p/9416831.html]中已经将常量池分析到了2/3了,接着把剩下的分析完,先回顾一下我们编译的源 ...

  3. android 进程/线程管理(一)----消息机制的框架

    一:android 进程和线程 进程是程序运行的一个实例.android通过4大主件,弱化了进程的概念,尤其是在app层面,基本不需要关系进程间的通信等问题. 但是程序的本质没有变,尤其是多任务系统, ...

  4. android 进程/线程管理(二)----关于线程的迷思

    一:进程和线程的由来 进程是计算机科技发展的过程的产物. 最早计算机发明出来,是为了解决数学计算而发明的.每解决一个问题,就要打纸带,也就是打点. 后来人们发现可以批量的设置命令,由计算机读取这些命令 ...

  5. android 进程/线程管理(四)续----消息机制的思考(自定义消息机制)

    继续分析handler 和looper 先看看handler的 public void dispatchMessage(Message msg) { if (msg.callback != null) ...

  6. 《java学习三》并发编程 -------线程池原理剖析

    阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到 ...

  7. android操作线程各种方法解析

    (一)刚开始学习android的时候我是这么写的 new Thread( new Runnable() { public void run() { myView.invalidate(); } }). ...

  8. Android UI线程和非UI线程

    Android UI线程和非UI线程 UI线程及Android的单线程模型原则 当应用启动,系统会创建一个主线程(main thread). 这个主线程负责向UI组件分发事件(包括绘制事件),也是在这 ...

  9. Android子线程真的不能更新UI么

    Android单线程模型是这样描述的: Android UI操作并不是线程安全的,并且这些操作必须在UI线程执行 如果在其它线程访问UI线程,Android提供了以下的方式: Activity.run ...

随机推荐

  1. UVA - 11604 General Sultan 题解

    题目大意: 有若干模式串,将某些模式串拼接起来(一个可以使用多次)形成一个长模式串,判断能否有两种或更多种不同的拼法拼成相同的模式串. 思路: 神奇的构图,暴力的求解. 可以发现,若有不同的拼法,则一 ...

  2. AR初体验:宣传G20

    最近Pokemon Go太火,它基于LBS(Location Based Service)+AR(Augmented Reality)的一款游戏,这股风,一定会让国内的公司纷纷效仿,你懂的.不可否定的 ...

  3. WPF-系统托盘

    WPFSystemTray.cs public class WPFSystemTray { /// <summary> /// 设置系统托盘 /// </summary> // ...

  4. S3C2440UART之FIFO

    一.基础知识 S3C2440有3个独立的串口,每一个都可以利用DMA和中断方式操作.每个包含2个64字节FIFO,一个收,一个发.非FIFO模式相当于FIFO模式的一个寄存器缓冲模式.每一个UART有 ...

  5. 在RNN中使用Dropout

    dropout在前向神经网络中效果很好,但是不能直接用于RNN,因为RNN中的循环会放大噪声,扰乱它自己的学习.那么如何让它适用于RNN,就是只将它应用于一些特定的RNN连接上.   LSTM的长期记 ...

  6. MongooseHelper

    /** * Created by lbc on 2016/11/16. */var mongoose=require("mongoose");var db=mongoose.con ...

  7. STM32之输入捕获以及小小应用(库)

    五一之际,先祝大家五一快乐.其实快乐很简单,工作的人有假放,学习的人也有假放,像我,有假放才有更多的时间学自己想学的东西.51假期学51,可惜没有32假期呀.好了..言归正传,大家听过吸星大法吧..在 ...

  8. win32进程名查找进程PID

    1. #include <Psapi.h> #pragma comment(lib, "Psapi.lib") DWORD GetProcIDFromName(LPCT ...

  9. Centos7 编译安装 Nginx PHP Mariadb Memcached 扩展 ZendOpcache扩展 (实测 笔记 Centos 7.3 + Mariadb 10.1.20 + Nginx 1.10.2 + PHP 7.1.0 + Laravel 5.3 )

    环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G,双网卡) 系统版本:CentOS-7-x86_64-Minimal-1611.iso 安装步骤: 1.准备 1.0 查看硬 ...

  10. 学习JavaScript闭包

    作者: 阮一峰 日期: 2009年8月30日 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面就是我的学习笔记,对于Javascript初 ...