EASY题

EP40-ThreadPool

2017-01-17  本文已影响10人  DrunkPian0

什么时候用线程池

线程池是为了在有很多线程的时候方便地管理线程。
手工定义的线程不能重复利用,每次使用都需要重新申请资源、启动线程,而线程创建和启动需要时间。

线程池通过缓存池预先创建一部分线程,需要的时候直接从里面取;用完之后线程池又把它回收再利用。
所以,应用场景是对性能要求较高、线程请求比较多的情况。

有三个好处;

  1. 通过reuse降低创建/销毁线程造成的资源消耗
  2. 线程提前创建好了,任务达到时,响应速度快
  3. 通过统一分配和控制,优化稳定性、资源消耗。

线程池类型

创建线程池可以直接用

new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

来构造,参数分别是:

也可以用Executors构造一种具体的线程池:

    /**
     * JDStock的RunningContext里的全局线程池
     */
    private static ThreadPoolExecutor sThreadPool = (ThreadPoolExecutor) Executors
            .newCachedThreadPool();

Executors.java类里的静态方法,可以创建很多不同类型的线程池。介绍三种常用的线程池。

给线程池提交任务的方法

  1. threadsPool.execute(new Runnable(){}) 没有返回值
  2. ExecutorServicesubmit方法。会返回future,用future.get()获取返回值,future.get()阻塞到任务完成,get(long timeout, TimeUnit unit)阻塞指定时间然后然会,无论任务有没有执行完。

线程池工作流程

ThreadPoolExecutor.java里的execute方法:
执行的三个step:

  1. 如果比corePoolSize个线程数少的线程正在运行,尝试用给的command创建一个新线程作为它的第一个task。否则进入2。

  2. 判断工作队列是否已满, 如果一个task可以成功加入队列,没满就把task加入这个队列。否则进入3。

  3. 不能入队,就判断整个线程池是否已满(MaximumPoolSize)。满了,就尝试创建一个新的线程。创建不了就拒绝task。

//ThreadPoolExecutor.java里的execute方法

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();

        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

Reference:
[1]http://ifeve.com/java-threadpool/

上一篇 下一篇

猜你喜欢

热点阅读