java 线程池

概述

  1. 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
  2. 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)
  3. 线程池使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务,减少创建和销毁线程的次数。

java 中提供了3种实现

  1. ThreadPoolExecutor:标准线程池
  2. ScheduledThreadPoolExecutor:支持延迟任务的线程池
  3. ForkJoinPool:类似于ThreadPoolExecutor,但是使用work-stealing模式,其会为线程池中的每个线程创建一个队列,从而用work-stealing(任务窃取)算法使得线程可以从其它线程队列里窃取任务来执行。既如果自己的任务处理完成了,则可以去忙碌的工作线程那里窃取任务执行。

1.ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler){
 ...... 
}
  • corePoolSize:核心线程池大小,线程池维护的线程最少线程。
  • maximumPoolSize:线程池最大大小。
  • keepAliveTime:线程池中线程的最大空闲时间,如果线程池中的线程个数大于corePoolSize,并且线程空闲时间超过该时间的线程会被回收。
  • unit: 线程池维护线程所允许的空闲时间的单位、可选参数值为:TimeUnit中的几个静态属性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。
  • workQueue: 线程池中存放工作任务的队列。常用的是:java.util.concurrent.ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue
  • threadFactory: 线程工厂,提供创建新线程的功能。ThreadFactory是一个接口,只有一个方法,通过线程工厂可以对线程的一些属性进行定制。
  • handler:线程池中的数量大于maximumPoolSize,对拒绝任务的处理策略,默认值ThreadPoolExecutor.AbortPolicy()。

Executors 提供了3个工厂方法创建 ThreadPoolExecutor

  1. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
}
  1. newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}
  1. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
}

2. ScheduledThreadPoolExecutor

我们通过查看ScheduledThreadPoolExecutor的源代码,可以发现ScheduledThreadPoolExecutor继承了ThreadPoolExecutor。

public ScheduledThreadPoolExecutor(int corePoolSize,
                                   ThreadFactory threadFactory,
                                   RejectedExecutionHandler handler) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue(), threadFactory, handler);
}

从构造中发现ScheduledThreadPoolExecutor线程池其实是调用了ThreadPoolExecutor构造进行实现的,只是ThreadPoolExecutor使用的工作队列是java.util.concurrent.ScheduledThreadPoolExecutor.DelayedWorkQueue通过名字我们都可以猜到这个是一个延时工作队列。 因为ScheduledThreadPoolExecutor的最大线程是Integer.MAX_VALUE,而且根据源码可以看到execute和submit其实都是调用schedule这个方法,而且延时时间都是指定为0,所以调用execute和submit的任务都直接被执行。

Executors 也提供了ScheduledThreadPoolExecutor创建方式

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

ScheduledThreadPoolExecutor 提供了3种延迟执行策略

  1. schedule(commod,delay,unit) ,这个方法是说系统启动后,需要等待多久执行,delay是等待时间。只执行一次,没有周期性。
  2. scheduleAtFixedRate(commod,initialDelay,period,unit),固定速率执行周期任务。这个是以period为固定周期时间,按照一定频率来重复执行任务,initialDelay是说系统启动后,需要等待多久才开始执行。
  3. scheduleWithFixedDelay(commod,initialDelay,delay,unit),固定延迟执行周期任务。这个是以delay为固定延迟时间,按照一定的等待时间来执行任务,initialDelay意义与上面的相同。

3. ForkJoinPool

在Java 7中引入了一种新的线程池:ForkJoinPool。 它同ThreadPoolExecutor一样,也实现了Executor和ExecutorService接口。它使用了一个无限队列来保存需要执行的任务,而线程的数量则是通过构造函数传入,如果没有向构造函数中传入希望的线程数量,那么当前计算机可用的CPU数量会被设置为线程数量作为默认值。

Executors 提供了 ForkJoinPool 的创建方式

public static ExecutorService newWorkStealingPool() {
    return new ForkJoinPool
        (Runtime.getRuntime().availableProcessors(),
         ForkJoinPool.defaultForkJoinWorkerThreadFactory,
         null, true);
}

并发数默认为当前系统cpu个数。

public static ExecutorService newWorkStealingPool(int parallelism) {
    return new ForkJoinPool
        (parallelism,
        ForkJoinPool.defaultForkJoinWorkerThreadFactory,
        null, true);
}

也可以指定并行数。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

Silverlight Telerik控件学习:数据录入、数据验证

相信很多人都听说过这句名言:garbage in ,garbage out ! 数据录入不规范(或错误)就象一颗定时炸弹,迟早会给系统带来麻烦,所以在数据录入时...

29760
来自专栏一名合格java开发的自我修养

java并发线程池---了解ThreadPoolExecutor就够了

总结:线程池的特点是,在线程的数量=corePoolSize后,仅任务队列满了之后,才会从任务队列中取出一个任务,然后构造一个新的线程,循环往复直到线程数量达到...

1.7K10
来自专栏haifeiWu与他朋友们的专栏

Java实现终止线程池中正在运行的定时任务

最近项目中遇到了一个新的需求,就是实现一个可以动态添加定时任务的功能。说到这里,有人可能会说简单啊,使用quartz就好了,简单粗暴。然而quartz框架太重了...

49030
来自专栏搜云库

使用 Executors,ThreadPoolExecutor,创建线程池,源码分析理解

之前创建线程的时候都是用的 newCachedThreadPoo,newFixedThreadPool,newScheduledThreadPool,newSi...

215100
来自专栏Linyb极客之路

并发编程之CyclicBarrier

一、CyclicBarrier简介 CyclicBarrier也叫同步屏障,在JDK1.5被引入,可以让一组线程达到一个屏障时被阻塞,直到最后一个线程达到屏...

30230
来自专栏xdecode

Java高并发之线程池详解

例如线程, jdbc连接等等, 在高并发场景中, 如果可以复用之前销毁的对象, 那么系统效率将大大提升.

17320
来自专栏移动开发面面观

Android线程池的详细说明(二)

26450
来自专栏Android相关

Java线程池---getTask方法解析

/** * Performs blocking or timed wait for a task, depending on * current confi...

35120
来自专栏小勇DW3

ThreadPoolExecutor 线程池的源码解析

  上一篇从整体上介绍了Executor接口,从上一篇我们知道了Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂...

14650
来自专栏刘望舒

Java高并发之线程池详解

在业务场景中, 如果一个对象创建销毁开销比较大, 那么此时建议池化对象进行管理。例如线程, jdbc连接等等, 在高并发场景中, 如果可以复用之前销毁的对象, ...

14350

扫码关注云+社区

领取腾讯云代金券