Java之线程池深度剖析

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的例子,以加深对原理的理解服务器

public final class ThreadPool {
     // 线程池中默认线程的个数为5
     private static int worker_num = 5;
     // 工做线程
     private WorkThread[] workThreads;
    
     // 任务队列,做为一个缓冲,List线程不安全
     private List<Runnable> taskQueue = new LinkedList<Runnable>();

     private static ThreadPool threadPool;

     // 建立具备默认线程个数的线程池
     private ThreadPool() {
          this(5);
     }

     // 建立线程池,worker_num为线程池中工做线程的个数
     private ThreadPool(int worker_num) {
          ThreadPool.worker_num = worker_num;
          workThreads = new WorkThread[worker_num];
          for (int i = 0; i < worker_num; i++) {
               workThreads[i] = new WorkThread();
               workThreads[i].start();// 开启线程池中的线程
          }
     }

     // 单态模式,得到一个默认线程个数的线程池
     public static ThreadPool getThreadPool() {
          return getThreadPool(ThreadPool.worker_num);
     }

     // 单态模式,得到一个指定线程个数的线程池,worker_num(>0)为线程池中工做线程的个数
     // worker_num<=0建立默认的工做线程个数
     public static ThreadPool getThreadPool(int worker_num1) {
          if (threadPool == null)
               threadPool = new ThreadPool(worker_num1);
          return threadPool;
     }

     // 执行任务,其实只是把任务加入任务队列,何时执行有线程池管理器觉定
     public void addTask(Runnable task) {
          synchronized (taskQueue) {
               taskQueue.add(task);
               taskQueue. notifyAll();
          }
     }

     // 销毁线程池,该方法保证在全部任务都完成的状况下才销毁全部线程,不然等待任务完成才销毁
     public void destroy() {
          while (!taskQueue.isEmpty()) {// 若是还有任务没执行完成,就先睡会吧
               try {
                    Thread.sleep(10);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
          }
          // 工做线程中止工做,且置为null
          for (int i = 0; i < worker_num; i++) {
               workThreads[i].stopWorker();
               workThreads[i] = null;
          }
          threadPool=null;
          taskQueue.clear();// 清空任务队列
     }

     /**
      * 内部类,工做线程
      */
     private class WorkThread extends Thread {
          // 该工做线程是否有效,用于结束该工做线程
          private boolean isRunning = true;

          /*
           * 关键所在啊,若是任务队列不空,则取出任务执行,若任务队列空,则等待
           */
          @Override
          public void run() {
               Runnable r = null;
               while (isRunning) {// 注意,若线程无效则天然结束run方法,该线程就没用了
                    synchronized (taskQueue) {
                         while (isRunning && taskQueue.isEmpty()) {// 队列为空
                              try {
                                   taskQueue.wait(20);
                              } catch (InterruptedException e) {
                                   e.printStackTrace();
                              }
                         }
                         if (!taskQueue.isEmpty())
                              r = taskQueue.remove(0);// 取出任务
                    }
                    if (r != null) {
                         r.run();// 执行任务
                    }
                    r = null;
               }
          }

          // 中止工做,让该线程天然执行完run方法,天然结束
          public void stopWorker() {
               isRunning = false;
          }
     }
}
相关文章
相关标签/搜索