线程池的原理及实现

转载 2015年11月20日 11:32:52

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1、线程池简介:</span>
    多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。   
    假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。

    如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
                一个线程池包括以下四个基本组成部分:
                1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
                2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
                3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
                4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
               
    线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
    线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
    假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

    代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了。

    package mine.util.thread;  
      
    import java.util.LinkedList;  
    import java.util.List;  
      
    /** 
     * 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息 
     */  
    public final class ThreadPool {  
        // 线程池中默认线程的个数为5  
        private static int worker_num = 5;  
        // 工作线程  
        private WorkThread[] workThrads;  
        // 未处理的任务  
        private static volatile int finished_task = 0;  
        // 任务队列,作为一个缓冲,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;  
            workThrads = new WorkThread[worker_num];  
            for (int i = 0; i < worker_num; i++) {  
                workThrads[i] = new WorkThread();  
                workThrads[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 (worker_num1 <= 0)  
                worker_num1 = ThreadPool.worker_num;  
            if (threadPool == null)  
                threadPool = new ThreadPool(worker_num1);  
            return threadPool;  
        }  
      
        // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
        public void execute(Runnable task) {  
            synchronized (taskQueue) {  
                taskQueue.add(task);  
                taskQueue.notify();  
            }  
        }  
      
        // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
        public void execute(Runnable[] task) {  
            synchronized (taskQueue) {  
                for (Runnable t : task)  
                    taskQueue.add(t);  
                taskQueue.notify();  
            }  
        }  
      
        // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
        public void execute(List<Runnable> task) {  
            synchronized (taskQueue) {  
                for (Runnable t : task)  
                    taskQueue.add(t);  
                taskQueue.notify();  
            }  
        }  
      
        // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁  
        public void destroy() {  
            while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧  
                try {  
                    Thread.sleep(10);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
            // 工作线程停止工作,且置为null  
            for (int i = 0; i < worker_num; i++) {  
                workThrads[i].stopWorker();  
                workThrads[i] = null;  
            }  
            threadPool=null;  
            taskQueue.clear();// 清空任务队列  
        }  
      
        // 返回工作线程的个数  
        public int getWorkThreadNumber() {  
            return worker_num;  
        }  
      
        // 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成  
        public int getFinishedTasknumber() {  
            return finished_task;  
        }  
      
        // 返回任务队列的长度,即还没处理的任务个数  
        public int getWaitTasknumber() {  
            return taskQueue.size();  
        }  
      
        // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数  
        @Override  
        public String toString() {  
            return "WorkThread number:" + worker_num + "  finished task number:"  
                    + finished_task + "  wait task number:" + getWaitTasknumber();  
        }  
      
        /** 
         * 内部类,工作线程 
         */  
        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();// 执行任务  
                    }  
                    finished_task++;  
                    r = null;  
                }  
            }  
      
            // 停止工作,让该线程自然执行完run方法,自然结束  
            public void stopWorker() {  
                isRunning = false;  
            }  
        }  
    }  
测试代码:
    package mine.util.thread;  
      
    //测试线程池  
    public class TestThreadPool {  
        public static void main(String[] args) {  
            // 创建3个线程的线程池  
            ThreadPool t = ThreadPool.getThreadPool(3);  
            t.execute(new Runnable[] { new Task(), new Task(), new Task() });  
            t.execute(new Runnable[] { new Task(), new Task(), new Task() });  
            System.out.println(t);  
            t.destroy();// 所有线程都执行完成才destory  
            System.out.println(t);  
        }  
      
        // 任务类  
        static class Task implements Runnable {  
            private static volatile int i = 1;  
      
            @Override  
            public void run() {// 执行任务  
                System.out.println("任务 " + (i++) + " 完成");  
            }  
        }  
    }  

运行结果:

WorkThread number:3  finished task number:0  wait task number:6
任务 1 完成
任务 2 完成
任务 3 完成
任务 4 完成
任务 5 完成
任务 6 完成
WorkThread number:3  finished task number:6  wait task number:0

分析:由于并没有任务接口,传入的可以是自定义的任何任务,所以线程池并不能准确的判断该任务是否真正的已经完成(真正完成该任务是这个任务的run方法执行完毕),只能知道该任务已经出了任务队列,正在执行或者已经完成。

2、java类库中提供的线程池简介:

     java提供的线程池更加强大,相信理解线程池的工作原理,看类库中的线程池就不会感到陌生了。



 

理解线程池的原理

线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。 ...
  • he90227
  • he90227
  • 2016年09月18日 17:45
  • 9149

[C++][线程池][完整实现] 转:线程池原理及创建(C++实现)

文章的主要框架是参考这篇文档的,http://jacky-dai.iteye.com/blog/1090285, 关于作者  张中庆,西安交通大学软件所,在读硕士,目前研究方向为分布式网络与移动中...
  • yfcheng_yzc
  • yfcheng_yzc
  • 2017年01月09日 19:14
  • 1865

Java ThreadPoolExecutor线程池原理及源码分析

一、源码分析(基于JDK1.6) ThreadExecutorPool是使用最多的线程池组件,了解它的原始资料最好是从从设计者(Doug Lea)的口中知道它的来龙去脉。在Jdk1.6中,Threa...
  • scherrer
  • scherrer
  • 2016年02月21日 17:27
  • 1164

线程池原理及创建并C++实现

本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进行了高层次的抽象,使之与具体的执行任务无关。另外该线程池具有动态伸缩性,它能根据执行任务的轻重自动调整线程池中线程的数量。文章的最后,我们...
  • shaderdx
  • shaderdx
  • 2016年12月16日 15:40
  • 4162

Java线程池原理及四种线程池的使用

Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFi...
  • honghailiang888
  • honghailiang888
  • 2016年06月16日 11:36
  • 4201

Android开发笔记之线程池的原理以及实现

声明: 转载与[http://blog.csdn.net/hsuxu/article/details/8985931]1.线程池的简介简介 1. 多线程技术主要解决处理器单元内多个线程执行的问题,...
  • u012416955
  • u012416955
  • 2016年08月04日 19:43
  • 1277

Java手写线程池实现

手写线程池实现1.线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。2.线程池简易架构3.简易线程池代码(自行优化)import jav...
  • yingfengjia520
  • yingfengjia520
  • 2017年10月14日 15:50
  • 164

python 线程池的研究及实现

http://www.cnblogs.com/coser/archive/2013/01/28/2581018.html    Python装饰器小结 http://www.cnblogs.com/...
  • q454684431
  • q454684431
  • 2013年08月19日 15:54
  • 7515

线程池原理(讲的非常棒)

Java并发编程:线程池的使用   在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:   如果并发的线程数量很多,并且每个线程都是执行一个时间...
  • gol_phing
  • gol_phing
  • 2015年10月10日 23:01
  • 8189

JDK之线程池介绍与原理

线程池组成 一个线程池包括以下四个基本组成部分:                 1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;      ...
  • YAOQINGGG
  • YAOQINGGG
  • 2015年01月07日 11:48
  • 1304
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:线程池的原理及实现
举报原因:
原因补充:

(最多只允许输入30个字)