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();
     }
 });




 

 
原文地址:https://www.cnblogs.com/dw3306/p/12551327.html