java封装的几个线程池介绍

java封装的几个线程池介绍

FixedThreadPool

FixedThreadPool并不是一个类,它是由Executors工具类创建出来的一个固定线程数的一个ThreadPoolEexcutor的对象,有2种实现方式。

Executors.newFixedThreadPool(3);//固定3个线程数

Executors.newFixedThreadPool(3, Executors.defaultThreadFactory());

我们来看下newFixedThreadPool()的内部实现吧

public static ExecutorService newFixedThreadPool(int nThreads) {
    //这里可以看出,返回的就是一个TreadPoolExecutor对象,不过这个对象的核心线程数和最大线程数相等
    return new ThreadPoolExecutor(nThreads, nThreads,
                              0L, TimeUnit.MILLISECONDS,
                              new LinkedBlockingQueue<Runnable>());
}


public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  //相比上面的方法,就是多了threadFactory参数
                                  threadFactory);
}

newFixedThreadPool()分析

这里就用一个参数的方法来分析。

  • corePoolSizemaxPoolSize都是参数nThreads:线程池中都是核心线程且是nThraeds个时,没有非核心线程。
  • 非工作线程的存活时间是0:当核心线程执行完队列中的任务时,如果队列中没有任务,这时核心线程死亡。极大程度的节约了系统资源。
  • 使用的队列默认最大值是Integer.MAX_VALUE:该队列长度是int最大值,相当于无限大了,这样不管你有多少任务,都能够存储在队列里面,等待核心线程去执行。

线程池中执行任务大致分为4个阶段

1.任务数小于核心线程数,如果在执行新任务,则创建核心线程去执行任务。

2.当核心线程都在执行任务时,未执行的任务且小于队列长度,这是任务会存储于队列中。

3.当核心线程都在执行任务,且未执行任务数大于队列长度,这是非核心线程会执行新的任务。

4.当核心线程都在执行任务,且未执行任务数大于队列长度,且非核心线程也在执行任务,这是会采用饱和策略。

newFixedPoolExecutor()创建出来的线程池,不会有第3阶段

FixedPoolExecutor的使用场景

FixedThreadPool适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器。


SingleThreadPool

SingleThreadPool是只有一个线程的线程池,内部实现和FixedThreadPool一样,不过就是线程数有区别。

SingleThreadPool的调用方法

Executors.newSingleThreadExecutor();

Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());

SingleThreadPool的内部实现

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService(
                            new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}


public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}

我们看到new FinalizableDelegatedExecutorService()对象包裹了一个ThreadPoolExecutor对象,这个ThreadPoolExecutor对象其实就是一个线程的FixedThreadPool,而FinalizableDelegatedExecutorService类就是对ThreadPoolExecutor在封装了一层。

所以我们也可以简单的理解为SingleThreadPool是只有一个线程的FixedThreadPool


CachedThreadPool

CachedThreadPool的调用方法

Executors.newCachedThreadPool();

Executors.newCachedThreadPool(Executors.defaultThreadFactory());

CachedThreadPool的内部实现

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0,Integer.MAX_VALUE,
                              60L, TimeUnit.SECONDS,
                              new SynchronousQueue<Runnable>());
}


public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>(),
                                  threadFactory);
}

newCachedThreadPool()中的ThreadPoolExecutor对象参数分析

  • corePoolSize核心线程数为0
  • maxPoolSize最大线程数为Integer.MAX_VALUE。
  • keepAliveTime:非工作线程存活时间60秒
  • workQueue:队列使用的SynchronousQueue(SynchronousQueue是一个没有容量的队列)。

通过参数我们可以知道,没有核心线程数,那么就不会走线程池的第一个阶段,SynchronousQueue队列是一个没有容量的阻塞队列。每个插入操作必须等待另一 个线程的对应移除操作。

下面看下CachedThreadPoolexecute()方法的执行示意图:

image

1.execute()首先执行SynchronousQueue.offer(Runnable r)。如果的当前maxPool中有空闲线程,会执行SynchronousQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS),那么主线程(调用execute()的线程)执行offer操作与空闲线程执行的poll操作配对成功。主线程把任务交给空闲线程执行,execute()方法执行完成。

2.当maxPool为空,或者maxPool中当前没有空闲线程时,将没有线程执行SynchronousQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)。这种情况下,步骤1失败。此时CachedThreadPool会创建一个新线程执行任务,execute()执行完成。

3.在步骤2中,新创建的线程将任务执行完后,会执行SynchronousQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)。这个poll操作会让空闲线程最多在SynchronousQueue中等待60秒,如果60秒钟内主线程提交了一个新任务(主线程执行步骤1),那么这个空闲线程将执行主线程提交的新任务;否则,这个空闲线程将终止。由于空闲60秒的空闲线程会被终止,因此长时间保持空闲的CachedThreadPool不会使用任何资源。

CachedThreadPool是大小无界的线程池,适用于执行很的短期异步任务的小程序,或者是负载较轻的服务器。


ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor是ThreadPoolExecutor的子类。

ScheduledThreadPoolEexcutor的调用有4中形式

Executors.newScheduledThreadPool(3);

Executors.newScheduledThreadPool(3, Executors.defaultThreadFactory());

new ScheduledThreadPoolExecutor(3);

new ScheduledThreadPoolExecutor(3, Executors.defaultThreadFactory());

其实Executors.newScheduledThreadPool(3)方法的内部实现也是直接创建一个对象,如:

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


public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1, threadFactory));
}

那我们接下来看下ScheduledThreadPoolExecutor()的构造方法实现

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}


public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue(), threadFactory);
}

从构造方法中可以知道,其实ScheduledThreadPoolExecutor调用的是父类中的构造方法,也就是ThreadPoolExecutor中的构造。那么我们来说说传入的参数:

  • corePoolSize:核心线程数,传入
  • 默认最大线程数为Integer.MAX_VALUE。
  • 保活时间默认10毫秒,DEFAULT_KEEPALIVE_MILLIS默认10L,单位毫秒。
  • 使用的队列是DelayedWorkQueueDelayedWorkQueue是一个无界限的队列,当添加的任务大于队列时,会从新增加队列的长度。同时DelayedWorkQueue还有着一套按超时时间升序排序的算法,遵循”左结点比右节点小(下次执行的时间更短)的原则。具体细节在下一章解释。

通过构造我们可以知道,ScheduledThreadPoolExecutorThreadPoolExecutor并没太多的区别,最大的区别就是队列的不同。因为DelayedWorkQueue的长度具有增长型和按超时时间升序排序算法,使得ScheduledThreadPoolExecutor具有延时执行任务的特性。

因为DelayedWorkQueue是属于无界队列,那么最大线程数设置Integer.MAX_VALUE就没有使用到。

ScheduledThreadPoolExecutor的执行方法

因为ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,所以会有execute()submit(),这里不介绍这2个方法。

ScheduledThreadPoolExecutor除了继承ThreadPoolExecutor,还实现了ScheduledExecutorService接口

ScheduledExecutorService接口方法

//创建任务并在给定延迟时间后执行
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);

//同上,只不过参数是Callable
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);

/**
 * 参数initialDelay:表示第一次延时的时间
 * 参数period:表示任务执行开始后距下一个任务开始执行的时间间隔
 */
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);

/**
 * 参数initialDelay:表示第一次延时的时间
 * 参数period:表示任务执行结束后距下一个任务开始执行的时间间隔
 */                                 
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);                                            

schedule()方法实现代码:

public ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();

    //decorateTask()的第2个参数,就是返回值,也就是即将延迟执行的任务对象
    RunnableScheduledFuture<Void> t = decorateTask(command,new ScheduledFutureTask<Void>(command, null,triggerTime(delay, unit),sequencer.getAndIncrement()));

    delayedExecute(t);//延迟执行这个任务
    return t;
}

//decorateTask()实现代码
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
    return task;
}

ScheduledThreadPoolExecutor的执行方法非常类似Timer定时器。

ScheduledThreadPoolExecutor的简单使用

  • schedule()的使用
public class Test {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3);

        System.out.println("任务执行前时间:" + System.currentTimeMillis());//任务执行前时间:1496847975977

        scheduledThreadPoolExecutor.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务执行时间:" + System.currentTimeMillis());//任务执行时间:1496847976993
            }
        }, 1000, TimeUnit.MILLISECONDS);
    }
}
  • scheduleAtFixedRate()的使用
public class Test {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3);

        System.out.println("任务执行前时间:" + System.currentTimeMillis());

        scheduledThreadPoolExecutor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务执行时间:" + System.currentTimeMillis());
                try {
                    Thread.sleep(1000);//这个是为了区别和下一个方法
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 1000, 5000, TimeUnit.MILLISECONDS);
    }
}


控制台打印结果:

任务执行前时间:1496848166272
任务执行时间:1496848167285     //第一次执行,任务延迟1秒执行
任务执行时间:1496848172281     //每隔5秒后执行任务
任务执行时间:1496848177280
任务执行时间:1496848182282
任务执行时间:1496848187282
  • scheduleWithFixedDelay()的使用
public class Test {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3);

        System.out.println("任务执行前时间:" + System.currentTimeMillis());//任务执行前时间:1496847975977

        scheduledThreadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务执行时间:" + System.currentTimeMillis());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 1000, 5000, TimeUnit.MILLISECONDS);
    }
}


打印结果:

任务执行前时间:1496848595162
任务执行时间:1496848596181     //第一次执行延时任务,延迟1秒
任务执行时间:1496848602188     //第2次执行任务,延迟大约6秒(5秒是延迟时间,1秒是任务执行的消耗时间)
任务执行时间:1496848608204
任务执行时间:1496848614211
任务执行时间:1496848620231
任务执行时间:1496848626256

ScheduledThreadPoolExecutor停止方法

  • shutdown()
  • shutdownNow()

这两个方法在将线程池ThreadPoolExecutor的时候介绍过。


SingleThreadScheduledExecutor

SingleThreadScheduledExecutorScheduledThreadPoolExecutor一样具有延时执行任务的特点。SingleThreadScheduledExecutor的内部实现就是ScheduledThreadPoolExecutor,只不过只有一个核心线程(虽然有最大线程数,但是队列的无边界的,所以除核心线程外,其他线程不会执行任务)。

SingleThreadScheduledExecutor的调用

Executors.newSingleThreadScheduledExecutor();

Executors.newSingleThreadScheduledExecutor(Executors.defaultThreadFactory());

SingleThreadScheduledExecutor的内部实现

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}


public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1, threadFactory));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值