Java巩固之路-----多线程(三)线程池的使用

实际的开发中,我们经常需要用到多线程,多线程能够有效提高并发量,提升CPU的使用率,但是,如果线程数量多的情况下,线程的创建和销毁也会产生一定的开销。为了解决这个问题,我们在实际开发中引用了线程池。

使用线程池,不得不说的就是ThreadPoolExecutor类。

ThreadPoolExecutor

 /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
public ThreadPoolExecutor(int corePoolSize,                 
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

看源码,看注释。

corePoolSize    核心线程数

maximumPoolSize    最大线程数

keepAliveTime          存活时间

timeUnit                    存活时间单位

workQueue               任务队列

threadFactory            线程工厂

rejectedExecutionHandler      拒绝策略

参数说明:

corePoolSize核心线程数。线程池开始工作,如果有新任务进来,当前线程数小于corepoolsize的时候就会直接创建线程去执行任务。

workQueue 工作队列。如果corepoolsize的线程都在工作,来了新任务,先加到队列中。

maximumPoolSize 最大线程数,工作中的线程数满了,同时队列也满了,还有新任务进来。如果Max任务数大于core任务数,那么就继续创建线程来执行任务。

rejectedExecutionHandler 拒绝策略。如果Max线程数满了,队列也满了。还有新的任务进来,那就要执行拒绝策略了。

拒绝策略:

AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
DiscardPolicy:也是丢弃任务,但是不抛出异常。
DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
CallerRunsPolicy:由调用线程处理该任务

上面三个很好理解,CallerRunsPolicy的意思是谁调用这个线程池谁来执行这个任务,比如说A线程往线程池中添加任务,线程池满了,执行了CallerRunsPolicy拒绝策略。那么就需要主线程自己来完成这个任务,后续的操作全部阻塞,等待主线程完成这个任务才会继续执行。

 

这是ThreadPoolExecutor构造参数最完整的一个构造方法。提供了最大程度的自定义创建的线程池方法。

这也是其他创建线程池方法的最底层实现。

然后,我们来说说Executors工具类。

在Executors中,根据使用场景不同可以创建四类线程池

线程池名称说明
singleThreadExecutor大小为1,先进先出的线程池
fixThreadPool大小用使用者自定义,队列先进先出线程池
cachedThreadPool初始大小为0,可无限扩展的线程池
scheduledThreadPool定长支持周期性工作的线程池

Executors.newSingleThreadExecutor();

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

singleThreadExecutor.

coresize,max,都为1,keepAliveTime为0S.队列使用的默认长度的LinkedBlockingQueue。一个Integer最大值的先进先出的队列。任意时刻最多只有一个任务在执行。

 

Executors.newFixedThreadPool(2);

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

创建一个核心线程数为2,最大线程数也为2的,无存活时间的,队列也是先进先出的linkedblockQueue。

根据使用者需要自定义的创建一个固定大小的线程池,无法扩容,任务执行完立即执行队列中下一个。

 

Executors.newCachedThreadPool();

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

创建一个核心线程数为0,最大线程数为Integer最大值的,允许无工作线程存活60S的,队列使用立即执行队列的线程池

因为最大线程数是无限大,核心线程数为0.意味着,只有有新的任务进来,就会启动一个工作线程去完成。当一个工作线程超过60S没有工作时,就关闭。cached可以根据任务数量完成自动扩容,任务少的时候,可以自动缩容。

 

Executors.newScheduledThreadPool(4);

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

newScheduledThreadPool会调用ScheduledThreadPoolExecutor的构造方法。就是上面代码部分。会创建一个核心线程数为0,最大线程数为Integer最大值,存活时间为0的使用DelayWorkQueue的线程池池。

具体怎么用,我也没用过,下次研究再上来补充。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值