您的位置:首页 > 编程语言 > Java开发

java线程深度解析(六)——线程池技术

2016-12-20 00:56 696 查看
http://blog.csdn.net/Daybreak1209/article/details/51382604

一种最为简单的线程创建和回收的方法:

[html] view
plain copy

 





new Thread(new Runnable(){  

             @Override  

            public void run() {  

                 while(true)  

                 {  

                     try {  

                        Thread.sleep(1000);//休息1s  

                    } catch (InterruptedException e) {  

                        e.printStackTrace();  

                    }  

                 }  

            }  

         }).start();  

     在run结束后,自动回收该线程 。但在真实生产环境中,可能会开启多个线程来支撑应用系统。创建和关闭都需要花费时间,并且再生产环境中,线程的数量必须合理控制,盲目的大量创建线程,对系统性能是有伤害的。为了节省多线程并发时不断创建和销毁线程所带来的额外开销,引入线程池。

     线程池的基本功能就是对线程进行复用。当接收一个任务等待处理时,先去线程池中查找是否有空闲线程,没有再创建新的线程;并且执行完毕后,将新建的线程放入线程池的空闲队列备用,而不直接销毁。

1、创建一个简易线程池

ThreadPool类:提供线程池创建、停止、添加线程、执行任务等方法

[html] view
plain copy

 





public class ThreadPool {  

    private static ThreadPool instance=null;  

    //空闲的县城队列  

    private List<PThread> idleThreads;  

    //已有的线程数  

    private int count;  

    private boolean isShutDown=false;  

      

    private ThreadPool()  

    {  

        this.idleThreads=new Vector(5);//类似于Arraylist  

        count=0;  

    }  

    public int getCreatedThread()  

    {  

        return count;  

    }  

      

    //取得线程实例  

    public synchronized static ThreadPool getInstance()  

    {  

        if(instance==null)  

            instance=new ThreadPool();  

            return instance;  

  

    }  

    //将线程放入线程池  

    public synchronized void putThread(PThread putThread)  

    {  

        if(!isShutDown)  

        {  

            idleThreads.add(putThread);  

        }else  

        {  

            putThread.shutDown();  

        }  

    }  

      

    //停止池中的所有线程  

    public synchronized void shotdown()  

    {  

        isShutDown=true;  

        for(int threadIndex=0;threadIndex<idleThreads.size();threadIndex++)  

        {  

            PThread idelThread=(PThread)idleThreads.get(threadIndex);  

            idelThread.shutDown();  

        }  

    }  

    //执行任务  

    public synchronized void start()  

    {  

        PThread thread=null;  

        //如果有空闲线程,直接使用  

        if(idleThreads.size()>0)  

        {  

            int lastIndex=idleThreads.size()-1;  

            thread=(PThread)idleThreads.get(lastIndex);  

            idleThreads.remove(lastIndex);  

            //立即执行这个任务  

            thread.setTarget(thread);  

        }else  

        {  

            //没有空闲线程,自己创建  

            count++;  

            thread=new PThread(target,count,this);  

            //启动这个线程  

            thread.start();  

        }  

              

    }  

}  

PThread类:模拟一个线程添加到线程池中,该线程只要不手动关闭,会一直等待任务并执行。

[html] view
plain copy

 





public class PThread extends Thread{  

    //线程池  

    private ThreadPool pool;  

    //任务  

    private Runnable target;  

    private boolean isShutDown=false;  

    private boolean isIdel=false;  

      

    //构造函数  

    public PThread(Runnable target,String name,ThreadPool pool)  

    {  

        super(name);  

        this.pool=pool;  

        this.target=target;  

    }  

    public  Runnable  getTarget() {  

        return target;  

    }  

    public boolean isIdle()  

    {  

        return isIdel;  

    }  

      

    @Override  

    public void run()  

    {  

        //只要不关闭,就一直不结束该线程  

        while(!isShutDown)  

        {  

            isIdel=false;  

            if(target !=null)  

            {  

                //运行任务  

                target.run();  

            }  

            //任务结束,到闲置状态  

            isIdel=true;  

            try {  

                //任务结束后,不关闭该线程,而放入线程池中闲置备用  

                pool.putThread(this);  

                synchronized (this) {  

                    //线程空闲,等待任务到来  

                    wait();  

                }  

          

            } catch (Exception e) {  

            }  

            isIdel=false;  

        }  

    }  

  

    public synchronized void setTarget(Runnable newTarget)  

    {  

        target=newTarget;  

        //设置任务之后,通知run方法,执行该任务  

        notifyAll();  

    }  

    //关闭线程  

    public synchronized void shutDown()  

    {  

        isShutDown=true;  

        notifyAll();  

    }  

}  

MyThread任务对象 and Client调用

2、JDK1.6中的内置线程池——Executor框架

       JDK中提供了一套Executor框架支持更好的控制多线程操作。在concurrent包中是并发线程的核心,其中ThreadPoolExecutor表示一个线程池,Executors扮演者线程池工厂的角色,通过Executors可以创建特定功能的线程池。

[html] view
plain copy

 





             //1、new一个固定线程数量的线程池,有一个新任务提交时,从该线程池中查找是否有空闲线程,如果没有新的任务会被暂存于一个任务队列中,待有空闲线程后再执行。  

ExecutorService threadPoolFix=Executors.newFixedThreadPool(3);//每次3个线程,执行3个任务;其他任务等待。     

//2、缓存线程池--返回一个跟任务数相等的线程数量,有多少任务就产生多少个线程进行处理。动态变化-干完了定期回收  

ExecutorService threadPoolCache=Executors.newCachedThreadPool();  

  

//3、只有一个线程的线程池,任务按照任务队列顺序FIFO执行,保证线程池始终中有一个线程,当前死了,立马搞一个顶替工作  

ExecutorService threadOne=Executors.newSingleThreadExecutor();  

  

//4、线程池大小为1,支持在给定时间执行某任务,如在某个固定的延时之后执行,或者周期性执行。-定时器效果  

ExecutorService threadSingleScheduled=Executors.newSingleThreadScheduledExecutor();  

  

//5、指定一定固定大小的线程池  

ExecutorService threadScheduled=Executors.newScheduledThreadPool(5);  

3、线程池优化

     线程池的大小对系统性能有着很大影响,过大过小都不利于程序运行。具体多大的线程池比较合适,可以借鉴《Java并发编程实战》中提供的一个计算公式:最优线程数量=CPU的数量*CPU的使用率*[1+(等待时间/计算时间)]。在java中通过Runtime.getRuntime().availableProcessors();获取可用CPU

4、自定义线程池

      jdk创建线程池对象大多继承于一个核心线程池类ThreadPoolExecutor,当采用自定义方式创建线程池时,也主要对这个类进行再封装。下面是ThreadPoolExecutor的核心构造方法:

[html] view
plain copy

 





public ThreadPoolExecutor(int corePoolSize,//线程池中线程数量  

                          int maximumPoolSize,//线程池中最大线程数  

                          long keepAliveTime,//当池中线程数超过corePoolSize时,多余线程多长时间内会被销毁  

                          TimeUnit unit,//keepAliveTime的时间单位  

                          BlockingQueue<Runnable> workQueue, //任务队列     

                          RejectedExecutionHandler handler //拒绝策略,当任务太多时,如何拒绝任务) {  

    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,  

         Executors.defaultThreadFactory(), handler);  

}    

任务队列workqueue用于存放Runnable对象,主要有以下几种实现:

1、直接提交的队列

2、有界的任务队列

3、无界的任务队列

4、优先任务队列

拒绝策略:

1、AbortPolicy:直接抛出异常,系统停止工作

2、CallerRunsPolicy:只要线程池未关闭,直接再运行被抛弃的任务

3、DiscardOledestPolicy:丢弃最老的一个任务请求

4、DiscardPolicy:丢弃无法处理的任务,不予处理

下面模拟一个任务排序基于优先任务队列:

[html] view
plain copy

 





public class DefinePool implements Runnable,Comparable<DefinePool>{  

    protected String name;  

      

    /*  

     * 构造方法  

     */  

    public DefinePool() {  

          

    }  

    public DefinePool(String name) {  

        this.name=name;  

    }  

  

    /*  

     * 模拟任务       

     */  

    @Override  

    public void run() {  

        try {  

            Thread.sleep(1000);  

            System.out.println("模拟任务!!!!!!name:"+name);  

        } catch (InterruptedException e) {  

            e.printStackTrace();  

        }  

    }  

      

    /*  

     * 比较任务优先级  

     */  

    @Override  

    public int compareTo(DefinePool o) {  

        //前提:线程名称标记优先级  

        int me=Integer.parseInt(this.name.split("_")[1]);  

        //System.out.println(me);  

          

        int other=Integer.parseInt(o.name.split("_")[1]);  

          

        if(me>other) return 1;  

        if(me<other) return -1;  

        else    return 0;  

    }  

}  

客户端调用类:

[html] view
plain copy

 





public class DefineClient {  

    public static void main(String[] args) {  

        ExecutorService exe = new ThreadPoolExecutor(100, 200, 0L,  

                TimeUnit.SECONDS, new PriorityBlockingQueue<Runnable>());  

        for(int i=0;i<1000;i++)  

        {  

            exe.execute(new DefinePool("testPoolext_"+Integer.toString(999-i)));  

        }  

    }  

}  

最终输出:

模拟任务!!!!!!name:testPoolext_914

模拟任务!!!!!!name:testPoolext_915
模拟任务!!!!!!name:testPoolext_916

模拟任务!!!!!!name:testPoolext_0


模拟任务!!!!!!name:testPoolext_1

模拟任务!!!!!!name:testPoolext_3

模拟任务!!!!!!name:testPoolext_5

模拟任务!!!!!!name:testPoolext_7

模拟任务!!!!!!name:testPoolext_6

模拟任务!!!!!!name:testPoolext_4

模拟任务!!!!!!name:testPoolext_2

模拟任务!!!!!!name:testPoolext_8

模拟任务!!!!!!name:testPoolext_12

模拟任务!!!!!!name:testPoolext_11

模拟任务!!!!!!name:testPoolext_10

模拟任务!!!!!!name:testPoolext_17

模拟任务!!!!!!name:testPoolext_16

模拟任务!!!!!!name:testPoolext_14

模拟任务!!!!!!name:testPoolext_15

模拟任务!!!!!!name:testPoolext_20

     从加粗部分为分界,前期程序刚启动,无需使用等待队列,故从任务序号999往下执行;当线程池中线程全部占用,任务开始进入任务队列,排队执行,使用优先任务队列,任务按照程序预定的从1~999优先级依次降低的顺序,将任务按优先级顺序依次放入任务队列。FIFO那么最先执行的就是最先放入队列的高优先级任务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: