Java线程池

来源:互联网 发布:淘宝国内专柜代购区分 编辑:程序博客网 时间:2024/05/16 14:32
Java 线程池的作用
现在服务器端的应用程序几乎都采用了“线程池”技术,这主要是为了提高系统效率。因为如果服务器对应每一个请求就创建一个线程的话,在很短的一段时间内就会产生很多创建和销毁线程动作,导致服务器在创建和销毁线程上花费的时间和消耗的系统资源要比花在处理实际的用户请求的时间和资源更多。线程池就是为了尽量减少这种情况的发生。 下面我们来看看怎么用Java实现一个线程池。一个比较简单的线程池至少应包含线程池管理器、工作线程、任务队列、任务接口等部分。其中线程池管理器(ThreadPool Manager)的作用是创建、销毁并管理线程池,将工作线程放入线程池中;工作线程是一个可以循环执行任务的线程,在没有任务时进行等待;任务队列的作用是提供一种缓冲机制,将没有处理的任务放在任务队列中;任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工作、任务的执行状态等,工作线程通过该接口调度任务的执行。
1.为什么要使用线程池
     在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。为了防止资源不足,服务器应用程序需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务,这就是“池化资源”技术产生的原因。
     线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整线程中的线程数目可以防止出现资源不足的情况。
2.线程池的组成部分
    一个比较简单的线程池至少应包含线程池管理器、工作线程、任务列队、任务接口等部分。其中线程池管理器的作用是创建、销毁并管理线程池,将工作线程放入线程池中;工作线程是一个可以循环执行任务的线程,在没有任务是进行等待;任务列队的作用是提供一种缓冲机制,将没有处理的任务放在任务列队中;任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工作、任务的执行状态等,工作线程通过该接口调度任务的执行。
      线程池管理器至少有下列功能:创建线程池,销毁线程池,添加新任务。
      工作线程是一个可以循环执行任务的线程,在没有任务时将等待。
      任务接口是为所有任务提供统一的接口,以便工作线程处理。任务接口主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等。
3.线程池适合应用的场合

      当一个服务器接受到大量短小线程的请求时,使用线程池技术是非常合适的,它可以大大减少线程的创建和销毁次数,提高服务器的工作效率。

线程池系列一:线程池作用及Executors方法讲解博客分类: Javajava多线程 线程池的作用:     线程池作用就是限制系统中执行线程的数量。     根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程 排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程 池中有等待的工作线程,就可以开始运行了;否则进入等待队列。 为什么要用线程池:减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)ThreadGroup与ThreadPoolExecutor的区别 我自己的理解也是一直以为ThreadGroup就是ThreadPoolExecutor(线程池),这是一个非常大的误会,最近把两者仔细分析了下。 线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。允许线程访问 有关自己的线程组的信息,但是不允许它访问有关其线程组的父线程组或其他任何线程组的信息;线程消耗包括内存和其它系统资源在内的大量资源。除了 Thread 对象所需的内存之外,每个线程都需要两个可能很大的执行调用堆栈。除此以外,JVM 可能会为每个 Java 线程创建一个本机线程,这些本机线程将消耗额外的系统资源。最后,虽然线程之间切换的调度开销很小,但如果有很多线程,环境切换也可能严重地影响程序的性 能。线程池是因为线程的生成关闭很浪费资源 所以不要频繁的操作 线程次 就是管理线程的地方 不用了它可以让它休眠也就是他替你管理线程 而且比你管理的要好的多。线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其 好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调 整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。 Executor详解: Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。ThreadPoolExecutor是Executors类的底层实现。我们先介绍下Executors。 Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利。为了编写高效稳定可靠的多线程程序,线程部分的新增内容显得尤为重要。   有关Java5线程新特征的内容全部在java.util.concurrent下面,里面包含数目众多的接口和类,熟悉这部分API特征是一项艰难的学习过程。目前有关这方面的资料和书籍都少之又少,大所属介绍线程方面书籍还停留在java5之前的知识层面上。   当然新特征对做多线程程序没有必须的关系,在java5之前通用可以写出很优秀的多线程程序。只是代价不一样而已。   线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。   在Java5之前,要实现一个线程池是相当有难度的,现在Java5为我们做好了一切,我们只需要按照提供的API来使用,即可享受线程池带来的极大便利。   Java5的线程池分好多种:固定尺寸的线程池、可变尺寸连接池。   在使用线程池之前,必须知道如何去创建一个线程池,在Java5中,需要了解的是java.util.concurrent.Executors类的API,这个类提供大量创建连接池的静态方法,是必须掌握的。 实例: 一、固定大小的线程池 Java代码  收藏代码import java.util.concurrent.Executors;    import java.util.concurrent.ExecutorService;    /**   * Java线程:线程池-   *   * @author Administrator 2009-11-4 23:30:44   */    public class Test {    public static void main(String[] args) {    //创建一个可重用固定线程数的线程池    ExecutorService pool = Executors.newFixedThreadPool(2);    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口    Thread t1 = new MyThread();    Thread t2 = new MyThread();    Thread t3 = new MyThread();    Thread t4 = new MyThread();    Thread t5 = new MyThread();    //将线程放入池中进行执行    pool.execute(t1);    pool.execute(t2);    pool.execute(t3);    pool.execute(t4);    pool.execute(t5);    //关闭线程池    pool.shutdown();    }    }    class MyThread extends Thread{    @Override    public void run() {    System.out.println(Thread.currentThread().getName()+"正在执行。。。");    }    }      pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-2正在执行。。。   Process finished with exit code 0   二、单任务线程池   在上例的基础上改一行创建pool对象的代码为:   //创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 Java代码  收藏代码ExecutorService pool = Executors.newSingleThreadExecutor();      输出结果为:       pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   Process finished with exit code 0   对于以上两种连接池,大小都是固定的,当要加入的池的线程(或者任务)超过池最大尺寸时候,则入此线程池需要排队等待。   一旦池中有线程完毕,则排队等待的某个线程会入池执行。   三、可变尺寸的线程池   与上面的类似,只是改动下pool的创建方式:   //创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。 Java代码  收藏代码ExecutorService pool = Executors.newCachedThreadPool();      pool-1-thread-5正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-4正在执行。。。   pool-1-thread-3正在执行。。。   pool-1-thread-2正在执行。。。   Process finished with exit code 0   四、延迟连接池 Java代码  收藏代码import java.util.concurrent.Executors;    import java.util.concurrent.ScheduledExecutorService;    import java.util.concurrent.TimeUnit;    /**   * Java线程:线程池-   *   * @author Administrator 2009-11-4 23:30:44   */    public class Test {    public static void main(String[] args) {    //创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。    ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口    Thread t1 = new MyThread();    Thread t2 = new MyThread();    Thread t3 = new MyThread();    Thread t4 = new MyThread();    Thread t5 = new MyThread();    //将线程放入池中进行执行    pool.execute(t1);    pool.execute(t2);    pool.execute(t3);    //使用延迟执行风格的方法    pool.schedule(t4, 10, TimeUnit.MILLISECONDS);    pool.schedule(t5, 10, TimeUnit.MILLISECONDS);    //关闭线程池    pool.shutdown();    }    }    class MyThread extends Thread {    @Override    public void run() {    System.out.println(Thread.currentThread().getName() + "正在执行。。。");    }    }        pool-1-thread-1正在执行。。。   pool-1-thread-2正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-2正在执行。。。   Process finished with exit code 0   五、单任务延迟连接池   在四代码基础上,做改动   //创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。   Java代码  收藏代码ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();      pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-1正在执行。。。   Process finished with exit code 0   六、自定义线程池   Java代码  收藏代码import java.util.concurrent.ArrayBlockingQueue;    import java.util.concurrent.BlockingQueue;    import java.util.concurrent.ThreadPoolExecutor;    import java.util.concurrent.TimeUnit;    /**   * Java线程:线程池-自定义线程池   *   * @author Administrator 2009-11-4 23:30:44   */    public class Test {    public static void main(String[] args) {    //创建等待队列    BlockingQueue bqueue = new ArrayBlockingQueue(20);    //创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。    ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,2,TimeUnit.MILLISECONDS,bqueue);    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口    Thread t1 = new MyThread();    Thread t2 = new MyThread();    Thread t3 = new MyThread();    Thread t4 = new MyThread();    Thread t5 = new MyThread();    Thread t6 = new MyThread();    Thread t7 = new MyThread();    //将线程放入池中进行执行    pool.execute(t1);    pool.execute(t2);    pool.execute(t3);    pool.execute(t4);    pool.execute(t5);    pool.execute(t6);    pool.execute(t7);    //关闭线程池    pool.shutdown();    }    }    class MyThread extends Thread {    @Override    public void run() {    System.out.println(Thread.currentThread().getName() + "正在执行。。。");    try {    Thread.sleep(100L);    } catch (InterruptedException e) {    e.printStackTrace();    }    }    }            pool-1-thread-1正在执行。。。   pool-1-thread-2正在执行。。。   pool-1-thread-2正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-2正在执行。。。   pool-1-thread-1正在执行。。。   pool-1-thread-2正在执行。。。   Process finished with exit code 0   创建自定义线程池的构造方法很多,本例中参数的含义如下:     ThreadPoolExecutor   public ThreadPoolExecutor(int corePoolSize,   int maximumPoolSize,   long keepAliveTime,   TimeUnit unit,   BlockingQueue workQueue)   用给定的初始参数和默认的线程工厂及处理程序创建新的 ThreadPoolExecutor。使用 Executors 工厂方法之一比使用此通用构造方法方便得多。   参数:   corePoolSize - 池中所保存的线程数,包括空闲线程。   maximumPoolSize - 池中允许的最大线程数。   keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。   unit - keepAliveTime 参数的时间单位。   workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。   抛出:   IllegalArgumentException - 如果 corePoolSize 或 keepAliveTime 小于零,或者 maximumPoolSize 小于或等于零,或者 corePoolSize 大于 maximumPoolSize。   NullPointerException - 如果 workQueue 为 null   自定义连接池稍微麻烦些,不过通过创建的ThreadPoolExecutor线程池对象,可以获取到当前线程池的尺寸、正在执行任务的线程数、工作队列等等。


0 0
原创粉丝点击