java多线程系列16-线程池

分析线程池前最好先了解下阻塞队列:java多线程系列15-阻塞队列

1.线程池

线程池大家平时都经常使用,使用线程池有什么好处:

  • 降低资源的消耗。降低线程创建和销毁的资源消耗
  • 提高响应速度:线程的创建时间为T1,执行时间T2,销毁时间T3,免去T1和T3的时间
  • 提高线程的可管理性

2.ThreadPoolExecutor

ThreadPoolExecutor,jdk所有线程池实现的基础。

2.1重要参数含义

int corePoolSize:线程池中核心线程数,< corePoolSize,就会创建新线程,= corePoolSize ,这个任务就会保存到BlockingQueue,如果调用prestartAllCoreThreads方法就会一次性的启动corePoolSize 个数的线程。
int maximumPoolSize, 允许的最大线程数,BlockingQueue也满了,< maximumPoolSize时候就会再次创建新的线程
long keepAliveTime, 线程空闲下来后,存活的时间,这个参数只在> corePoolSize才有用
TimeUnit unit, 存活时间的单位值
BlockingQueue workQueue, 保存任务的阻塞队列
ThreadFactory threadFactory, 创建线程的工厂,给新建的线程赋予名字
RejectedExecutionHandler handler :饱和策略
AbortPolicy :直接抛出异常,默认;
CallerRunsPolicy:用调用者所在的线程来执行任务
DiscardOldestPolicy:丢弃阻塞队列里最老的任务,队列里最靠前的任务
DiscardPolicy :当前任务直接丢弃
实现自己的饱和策略,实现RejectedExecutionHandler接口即可
线程池状态:
Running:接收新任务并且处理进入阻塞队列的任务。
SHUTDOWN:不接受新任务,但处理进入阻塞队列的任务。
STOP:不接受任务,不处理进入阻塞队列的任务并且中断正在执行的任务。
TIDYING:所有的任务都已经终止,workerCount为0,线程转化为TIDYING状态并且调用terminated钩子函数。
TERMINATED:terminated钩子函数已经运行完成。

2.2 execute方法

该方法不需要返回值
(1)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();
        }
        //如果线程池还在运行并且command加入队列成功
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            //再次检查,如果线程池不再处于运行状态,删除任务成功
            if (! isRunning(recheck) && remove(command))
            	//拒绝任务
                reject(command);
            //如果线程池还在运行,任务加入队列成功,但线程数量为0,启动一个线程
            //或者如果线程池不处于运行,任务删除失败(有其他线程把任务执行了)
            else if (workerCountOf(recheck) == 0)
            	//第二个参数为true代表占用corePoolSize,false占用maxPoolSize
                addWorker(null, false);
        }
        //线程池如果处于shutdown以上状态,这时候addWorker肯定不成功
        //线程池还在运行,阻塞队列已经满,占用maxPoolSize数量,增加任务
        else if (!addWorker(command, false))
        	//如果失败拒绝任务
            reject(command);
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
    }

execute方法可以线程池执行的主流程:

  • 如果线程池中线程数量小于核心线程池数量,增加线程执行任务
  • 如果到达核心线程数量,加入阻塞队列
  • 如果阻塞队列已满,再次增加线程数量执行任务
  • 如果线程数量到达线程最大数量,拒绝任务
    (2)addWorker
  private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            //当前线程的状态
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //如果线程状态大于SHUTDOWN或者处于SHUTDOWN时,需要添加任务,返回失败
            //如果处于SHUTDOWN时,不需要添加任务,队列为空,返回失败
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                //线程数量超出范围,添加失败
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //增加worker数量
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                //线程池状态发生变化,重试
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                //加锁是为保证worker数量是线程按照的
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());
                    //
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        //线程池曾经已有线程的最大数量
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

addWorker实际就是增加线程数量,代码前面部分都是判断

  • 如果线程池目前已经处于shutdown及以上状态,不能向线程池添加任务。如果线程池处于shutdown,队列为空,不添加任务,只增加线程也不可以
  • 如果预计增加的是核心线程,但核心线程数量已满,失败。如果增加的不是核心线程,但数量数量已经到达最大值,失败
  • 如果以上判断通过,创建worker,启动线程执行任务
    (3)addWorkerFailed方法
    private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                workers.remove(w);
            decrementWorkerCount();
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

addWorkerFailed是增加线程失败后,从workers中去除,减少worker数量,尝试中断线程池
(4)tryTerminate方法

    final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            //线程池正在运行,不能终止
            //或者所有任务都已经结束,不需要终止
            //线程池为SHUTDOWN并且工作队列不为空,不能终止
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            //进入到这一步,只有两种情况:线程池为SHUTDOWN并且工作队列为空或者线程池为stop
            //如果这时候线程池数量不为空,尝试中断一个空闲线程
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
            	//将线程池状态设为TIDYING状态,准备调用钩子函数
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                    	//将线程池状态设为TERMINATED状态,调用钩子函数结束
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

tryTerminate方法是尝试中断线程,如果条件不满足,不中断或者减少一个空闲线程。如果以上条件不满足,工作队列夜空了,正式开始终止线程。
(5)interruptIdleWorkers
中断空线程首先要获得锁,因为正在执行的任务会持有锁

    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                //如果获取尝试中断线程
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                //只终止一个线程
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

(6)线程执行run方法

        public void run() {
            runWorker(this);
        }

(7)runWorker方法

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        //释放锁后,线程可以被中断
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
        	//如果传入任务不为空或者可以从工作队列获取任务
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                //线程池状态大于等于STOP,需要中断当前线程
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                	//重置线程中断信号
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                    	//执行任务
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

(8)getTask方法从阻塞队列取任务

    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //线程池状态大于SHUTDOWN,或者处于SHUTDOWN工作队列为空
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            	//减少worker数量
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            //如果线程数量超过核心线程数或者线程任务取任务超时,并且队列为空或者线程数量大于1,尝试减少worker数量
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
            	//从工作队列获取任务
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                //获取任务超时
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

(9)processWorkerExit
work结束时执行内容:尝试终止线程池或者线程池还需运行,判断是否需要增加线程

    private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        	//异常中断,减少worker数量
        	decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
        	//统计完成任务数量
            completedTaskCount += w.completedTasks;
            //移除work
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
        //尝试中断线程
        tryTerminate();

        int c = ctl.get();
        //线程池状态处于中断及以下
        if (runStateLessThan(c, STOP)) {
        	//如果线程非异常中断
            if (!completedAbruptly) {
            	//线程池应该拥有的最小线程数量
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                //线程池数量足够
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            //线程异常中断或者线程池数量不够,增加线程
            addWorker(null, false);
        }
    }

(10)shutdown方法
设置线程池的状态,只会中断所有没有执行任务的线程。

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
        	//判断调用者是否有权限关闭现场
            checkShutdownAccess();
            //循环设置线程池状态为shutdown
            advanceRunState(SHUTDOWN);
            //中断所有空闲线程,只是打个标记
            interruptIdleWorkers();
            //钩子函数
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        //尝试中断线程
        tryTerminate();
    }

(11)shutdownNow方法

    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
        	//判断停止线程池权限
            checkShutdownAccess();
            //线程池状态设为STOP
            advanceRunState(STOP);
            //中断所有线程
            interruptWorkers();
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

2.3 submit方法

平时我们用线程池submit和execute不同点是submit方法有返回值。但在ThreadPoolExecutor中我们没有看到submit方法。
执行上在execute中线程执行runWorker给我们提供了两个钩子函数: beforeExecute(wt, task)和afterExecute(task, thrown)方法。我们可以在afterExecute中进行实现取的返回值,比如:

	class ExtendedExecutor extends ThreadPoolExecutor {
	        // ...
	        protected void afterExecute(Runnable r, Throwable t) {
	          super.afterExecute(r, t);
	          if (t == null && r instanceof Future<?>) {
	            try {
	              Object result = ((Future<?>) r).get();
	            } catch (CancellationException ce) {
	                t = ce;
	            } catch (ExecutionException ee) {
	                t = ee.getCause();
	            } catch (InterruptedException ie) {
	                Thread.currentThread().interrupt(); // ignore/reset
	            }
	          }
	          if (t != null)
	            System.out.println(t);
	        }
	      }}

2.4 handler

handler: 当queue满了和线程数达到最大限制,对于继续到达的任务采取的策略。默认采取AbortPolicy , 也就是拒绝策略。

  • AbortPolicy:默认的拒绝策略,当继续有任务到来时直接抛出异常
    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
  • DiscardPolicy:rejectedexecution是个空方法,意味着直接抛弃该任务,不处理。
    public static class DiscardPolicy implements RejectedExecutionHandler {
    /**
    * Creates a {@code DiscardPolicy}.
    */
    public DiscardPolicy() { }

     /**
      * Does nothing, which has the effect of discarding task r.
      *
      * @param r the runnable task requested to be executed
      * @param e the executor attempting to execute this task
      */
     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
     }
    

    }

  • DiscardOldestPolicy:除非调用了shutdown方法,否则。抛弃queue中的第一个任务,再次执行该任务。

    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
  • CallerRunsPolicy:直接由执行该方法的线程继续执行该任务,除非调用了shutdown方法,这个任务才会被丢弃,否则继续执行该任务会发生阻塞。
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

总结,线程池的执行步骤如图所示:
在这里插入图片描述

3. Executors

Executors中提供了几种不同的线程池。

3.1 FixedThreadPool

创建固定线程数量的,适用于负载较重的服务器,使用了无界队列(其实还是有界,只有最大值很大,Integer.MAX_VALUE)。

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

3.2 SingleThreadExecutor

创建单个线程,需要顺序保证执行任务,不会有多个线程活动,使用了无界队列。

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

3.3 CachedThreadPool

会根据需要来创建新线程的,执行很多短期异步任务的程序,使用了SynchronousQueue。

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

3.4 WorkStealingPool

基于ForkJoinPool实现。

    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

4. ScheduledThreadPoolExecutor

这里说下另外一个具有定时执行任务功能的线程池。
newSingleThreadScheduledExecutor:只包含一个线程,只需要单个线程执行周期任务,保证顺序的执行各个任务
newScheduledThreadPool 可以包含多个线程的,线程执行周期任务,适度控制后台线程数量的时候
方法说明:
schedule:只执行一次,任务还可以延时执行
scheduleAtFixedRate:提交固定时间间隔的任务
scheduleWithFixedDelay:提交固定延时间隔执行的任务
ScheduledThreadPoolExecutor也是基于ThreadPoolExecutor实现的线程池,只是有定时功能,队列也是用了类似优先级队列的思想,没加入一个队列会进行排序,按照延迟时间最短的排序在头部。

4.1 FutureTask

定时任务中内部任务类ScheduledFutureTask继承了FutureTask,这里简单介绍下:
(1)FutureTask的状态
NEW:表示这是一个新的任务,或者还没有执行完的任务,是初始状态。
COMPLETING:表示任务执行结束(正常执行结束,或者发生异常结束),但是还没有将结果保存到outcome中。是一个中间状态。
NORMAL:表示任务正常执行结束,并且已经把执行结果保存到outcome字段中。是一个最终状态。
EXCEPTIONAL:表示任务发生异常结束,异常信息已经保存到outcome中,这是一个最终状态。
CANCELLED:任务在新建之后,执行结束之前被取消了,但是不要求中断正在执行的线程,也就是调用了cancel(false),任务就是CANCELLED状态,这时任务状态变化是NEW -> CANCELLED。
INTERRUPTING:任务在新建之后,执行结束之前被取消了,并要求中断线程的执行,也就是调用了cancel(true),这时任务状态就是INTERRUPTING。这是一个中间状态。
INTERRUPTED:调用cancel(true)取消异步任务,会调用interrupt()中断线程的执行,然后状态会从INTERRUPTING变到INTERRUPTED。
(1)run方法

    public void run() {
    	//线程还没运行或者线程运行还没结束
    	//线程执行者设为自己
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                	//设置结果
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
            	//如果线程处于正在中断还未结束,需要等待线程中断结束
                handlePossibleCancellationInterrupt(s);
        }
    }

(2)finishCompletion

    private void finishCompletion() {
        // assert state > COMPLETING;
    	//唤醒等待结果线程
        for (WaitNode q; (q = waiters) != null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
      //执行钩子函数
        done();

        callable = null;        // to reduce footprint
    }

(3)awaitDone方法

    private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }

            int s = state;
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING) // cannot time out yet
                Thread.yield();
            else if (q == null)
                q = new WaitNode();
            else if (!queued)
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                     q.next = waiters, q);
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                LockSupport.parkNanos(this, nanos);
            }
            else
                LockSupport.park(this);
        }
    }

4.2 FutureTask

(1)构造函数

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

(2)再看下只执行一次方法schedule

    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        //方法返回的就是传入的第二个值ScheduledFutureTask
        //ScheduledFutureTask构造函数的triggerTime值是为后续排序准备
        RunnableScheduledFuture<?> t = decorateTask(command,
            new ScheduledFutureTask<Void>(command, null,
                                          triggerTime(delay, unit)));
        //如果线程池没有shutdown话,将任务加入队列,并且预先启动足够多的线程
        delayedExecute(t);
        return t;
    }

(3)delayedExecute方法

   private void delayedExecute(RunnableScheduledFuture<?> task) {
        //线程是否在运行,没有在运行拒绝加入队列
    	if (isShutdown())
            reject(task);
        else {
        	//任务加入队列
            super.getQueue().add(task);
            //线程不再运行,需要判断在当前状态下任务是否可以继续运行
            //如果不可以,从阻塞队列删除任务
            if (isShutdown() &&
                !canRunInCurrentRunState(task.isPeriodic()) &&
                remove(task))
            	//任务设置为取消
            	task.cancel(false);
            else
            	//预先启动足够线程
                ensurePrestart();
        }
    }

(4)scheduleAtFixedRate方法
提交固定时间间隔的任务

    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (period <= 0)
            throw new IllegalArgumentException();
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(period));
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        sft.outerTask = t;
        delayedExecute(t);
        return t;
    }

看上去好像和上边执行一次方法没有什么区别,看不出来怎么周期性运行,其实周期执行关键在任务的run方法。
(5)ScheduledFutureTask的run方法

        public void run() {
        	//是否需要周期执行
            boolean periodic = isPeriodic();
            //当前线程状态是否可以执行任务
            if (!canRunInCurrentRunState(periodic))
            	//不能周期性执行,取消任务
                cancel(false);
            else if (!periodic)
            	//不需要周期性执行任务,运行一次
                ScheduledFutureTask.super.run();
            else if (ScheduledFutureTask.super.runAndReset()) {
            	//任务执行完毕,并且并未取消或者中断
            	//设值下一次执行时间
                setNextRunTime();
                //把当前任务再次加入队列
                reExecutePeriodic(outerTask);
            }
        }

(6)reExecutePeriodic方法

    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
    	//当前线程如果可以运行任务
        if (canRunInCurrentRunState(true)) {
        	//任务加入队列
            super.getQueue().add(task);
            //如果线程不能运行取消任务
            if (!canRunInCurrentRunState(true) && remove(task))
                task.cancel(false);
            else
            	//确保有足够线程执行任务
                ensurePrestart();
        }
    }

(7)scheduleWithFixedDelay方法
提交固定延时间隔执行的任务

    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (delay <= 0)
            throw new IllegalArgumentException();
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(-delay));
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        sft.outerTask = t;
        delayedExecute(t);
        return t;
    }

这时候又是不是又有点疑惑了,这个和执行固定时间间隔的区别在哪,其实是在设置下一次执行时间上。
(8)setNextRunTime

        private void setNextRunTime() {
            long p = period;
            //p大于0,代表固定时间间隔
            //p小于0,代表固定延迟间隔
            if (p > 0)
            	//上次开始时间加上时间间隔
                time += p;
            else
            	//当前时间加上时间间隔
                time = triggerTime(-p);
        }

5.线程池大小

根据任务的性质来:计算密集型(CPU),IO密集型,混合型
计算密集型:加密,大数分解,正则……., 线程数适当小一点,最大推荐:机器的Cpu核心数+1,为什么+1,防止页缺失,(机器的Cpu核心=Runtime.getRuntime().availableProcessors()?
IO密集型:读取文件,数据库连接,网络通讯, 线程数适当大一点,机器的Cpu核心数*2,
混合型:尽量拆分,IO密集型>>计算密集型,拆分意义不大,IO密集型~计算密集型
队列的选择上,应该使用有界,无界队列可能会导致内存溢出,OOM

6.ExecutorCompletionService

ExecutorCompletionService实际上只是做了一次封装,内部有个阻塞队列封装了已经完成的任务,主要利用FutureTask完成时的钩子函数done方法,将完成的任务放入队列。
这样防止在原有线程中,因为中间一个线程执行时间比较长,导致后续已经完成的任务无法取得结果。

  public ExecutorCompletionService(Executor executor) {
        if (executor == null)
            throw new NullPointerException();
        this.executor = executor;
        this.aes = (executor instanceof AbstractExecutorService) ?
            (AbstractExecutorService) executor : null;
        this.completionQueue = new LinkedBlockingQueue<Future<V>>();
    }
    private class QueueingFuture extends FutureTask<Void> {
        QueueingFuture(RunnableFuture<V> task) {
            super(task, null);
            this.task = task;
        }
        protected void done() { completionQueue.add(task); }
        private final Future<V> task;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值