java 线程池

原创
2018/06/23 17:23
阅读数 304

概述

  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 评论
2 收藏
1
分享
返回顶部
顶部