EP40-ThreadPool

什么时候用线程池

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

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

有三个好处;

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

线程池类型

创建线程池可以直接用

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

来构造,参数分别是:

  • int corePoolSize:pool中keep的线程数量,包括idle的
  • int maximumPoolSize:允许的最多线程数量
  • long milliseconds当线程数量超过了corePoolSize,超出部分的idle线程允许的最大停留时间
  • BlockingQueue workQueue等待执行的Task队列

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

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

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

  • SingleThreadExecutor
    只包含一个线程的线程池。适用于每次只使用一个线程的情况。任务会依次执行。
    创建方法:Executors.newSingleThreadExecutor()

  • CachedThreadPool
    这个线程池,只要有创建线程的需要,就创建新的线程。会重用之前构造的可用的线程,如果有需要,就用ThreadFactory创建新的线程。如果线程数目过多,不适合用这个线程池,因为会占用很多资源。适合线程数量不是特别多的情况。
    创建方法:Executors.newCachedThreadExecutor()

  • FixedThreadPool
    重用(reuse)固定数量的线程。在任何时间点都只能有指定数量的线程处理任务。如果有其他任务提交了,所有的线程又都已经是active的了,这些任务(Task)会在队列里等着,直到有一个线程可用了。这个线程池会一直存在,直到执行了ExecutorService.shutdown

给线程池提交任务的方法

  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/

你可能感兴趣的:(EP40-ThreadPool)