zoukankan      html  css  js  c++  java
  • java线程池使用

    java线程池使用

    线程池:

         之前我们在使用多线程都是用Thread的start()来创建启动一个线程,但是在实际开发中,如果每个请求到达就创建一个新线程,开销是相当大的。服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。这就引入了线程池概念。

    优点:

    (1) 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗;

    (2) 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行;

    (3) 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。


    Executors提供四种线程池

    ExecutorService ex = Executors.newCachedThreadPool();
    ExecutorService ex = Executors.newFixedThreadPool(poolSize)

    使用线程池:

    • 1、创建线程池

    • 2、创建任务

    • 3、执行任务

    • 4、关闭线程池

    ThreadPoolExecutor

              在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险

    构造函数的定义:

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) ;
    • corePoolSize
      线程池大小,决定着新提交的任务是新开线程去执行还是放到任务队列中,也是线程池的最最核心的参数。一般线程池开始时是没有线程的,只有当任务来了并且线程数量小于corePoolSize才会创建线程。
    • maximumPoolSize
      最大线程数,线程池能创建的最大线程数量。
    • keepAliveTime
      在线程数量超过corePoolSize后,多余空闲线程的最大存活时间。
    • unit
      keepAliveTime的时间单位
    • workQueue
      存放来不及处理的任务的队列,是一个BlockingQueue。
    • threadFactory
      生产线程的工厂类,可以定义线程名,优先级等。
    •   handler     拒绝策略,当任务来不及处理的时候,如何处理。
    1、 AbortPolicy -- 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。
    2、 CallerRunsPolicy -- 当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。
    3、 DiscardOldestPolicy -- 当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
    4、 DiscardPolicy -- 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝 的任务。
     
    1:有界的任务队列:有界的任务队列可以使用ArrayBlockingQueue实现
     
    pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

    2、无界的任务队列:有界任务队列可以使用LinkedBlockingQueue实现,如下所示

    pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

    自定义拒绝策略
      pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5),
                    Executors.defaultThreadFactory(), new RejectedExecutionHandler() {
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    System.out.println(r.toString()+"执行了拒绝策略");
                    
                }
            });
     

    创建任务:

    任务分为两种:一种是有返回值的( callable,一种是没有返回值的( runnable. Callable与 Future 两功能是Java在后续版本中为了适应多并法才加入的,Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务。

    • 无返回值的任务就是一个实现了runnable接口的类.使用run方法.
    • 有返回值的任务是一个实现了callable接口的类.使用call方法.

    Callable和Runnable的区别如下:

    • Callable定义的方法是call,而Runnable定义的方法是run。
    • Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。
    • Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常。

    执行任务

          通过java.util.concurrent.ExecutorService接口对象来执行任务,该对象有两个方法可以执行任务execute和submit。execute这种方式提交没有返回值,也就不能判断是否执行成功。submit这种方式它会返回一个Future对象,通过future的get方法来获取返回值,get方法会阻塞住直到任务完成。

    execute与submit区别:

    • 接收的参数不一样
    • submit有返回值,而execute没有
    • submit方便Exception处理
    • execute是Executor接口中唯一定义的方法;submit是ExecutorService(该接口继承Executor)中定义的方法
    使用线程池
    (1)调用Runnable
    pool.execute(new Runnable() {
        @Override
        public void run() {
            // 输出内容:MyThreadFactory_testThread_0
            System.out.println(Thread.currentThread().getName());
        }
    });
     
    (2)调用callable
    Future<String> future = pool.submit(new Callable<String>() {
         @Override
         public String call() throws Exception {
             return Thread.currentThread().getName();
         }
     });




     

     
  • 相关阅读:
    OGRE源代码resource分析
    全排列
    各种让人无语的库
    python Kmeans算法
    Linux服务器安装MariaDB数据库
    初探SEO,BSP收录速度测试
    MetaWeblog API调用
    Patterns
    腾讯。。。对Linux的支持程度直接扼杀了Linux在国内用户群的增长
    个人电子商务网站建设之——整站静态化实现的选择、设计与实现(二):静态页面的实现方式;
  • 原文地址:https://www.cnblogs.com/dw3306/p/12551327.html
Copyright © 2011-2022 走看看