ScheduledThreadPoolExecutor

ScheduledFutureTask

run

public void run() {
    // 首先判断是否是周期性任务
    boolean periodic = isPeriodic();
    // 如果该任务不能再当前的线程池状态下运行,那么取消任务
    if (!canRunInCurrentRunState(periodic))
        cancel(false);
    // 如果不是周期性任务,那么该任务就是个普通的FutureTask,直接调用父类的run
    else if (!periodic)
        ScheduledFutureTask.super.run();
    // 到这里,说明是周期性任务,那么执行且重置任务
    else if (ScheduledFutureTask.super.runAndReset()) {
        // 计算下个周期
        setNextRunTime();
        // 
        reExecutePeriodic(outerTask);
    }
}

reExecutePeriodic

void reExecutePeriodic(RunnableScheduledFuture<?> task) {   
    // 如果当前线程池状态允许执行周期性任务
    if (canRunInCurrentRunState(true)) {
        // 将该任务重新再假如到任务列表中
        super.getQueue().add(task);
        // 如果现在线程池状态又不允许了,那么从任务列表中移除该任务,且取消执行
        if (!canRunInCurrentRunState(true) && remove(task))
            task.cancel(false);
        else
            // 否则新增工作线程,worker会自己去拿任务
            ensurePrestart();
    }
}

delayedExecute

private void delayedExecute(RunnableScheduledFuture<?> task) {
    // 如果线程池已经SHUTDOWN,那么执行拒绝策略
    if (isShutdown())
        reject(task);
    else {
        // 将任务加到任务列表中
        super.getQueue().add(task);
        
        // 如果线程池是SHUTDOWN,且任务不能再SHUTDOWN之后继续执行
        // 那么这个任务没有存在的意义,从队列中删除该任务,并尝试取消任务执行
        if (isShutdown() &&  
            !canRunInCurrentRunState(task.isPeriodic()) &&
            remove(task))
            task.cancel(false);
        else
            // 添加工作线程,worker会自己去拿任务
            ensurePrestart();
    }
}

ensurePrestart

void ensurePrestart() {
    // 拿到工作线程数
    int wc = workerCountOf(ctl.get());
    // 如果小于核心线程数,那么增加工作线程,worker会自己去拿任务
    if (wc < corePoolSize)
        addWorker(null, true);
    else if (wc == 0)
        addWorker(null, false);
}

DelayedWorkQueue

offer

public boolean offer(Runnable x) {
    if (x == null)
        throw new NullPointerException();
    RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>)x;
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        int i = size;
        // 如果超过queue的长度,那么扩容
        if (i >= queue.length)
            grow();
        // 否则长度加一
        size = i + 1;
        // 如果当前队列为空,那么该任务作为首节点
        if (i == 0) {
            queue[0] = e;
            setIndex(e, 0);
        // 否则做堆上浮的操作,将该任务放在二叉堆中合适的位置
        } else {
            siftUp(i, e);
        }
        // 经过上面的操作,如果当前队列的首节点是当前任务,那么唤醒一个等待线程开始处理
        // 如果首节点,不是当前任务的话,那么这里只是插入,不做唤醒
        if (queue[0] == e) {
            leader = null;
            available.signal();
        }
    } finally {
        lock.unlock();
    }
    return true;
}

take

public RunnableScheduledFuture<?> take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    // 先锁队列
    lock.lockInterruptibly();
    try {
        for (;;) {
            // 拿到首节点
            RunnableScheduledFuture<?> first = queue[0];
            // 如果首节点为空,那么等待,直到有任务为止
            // Leader-Follower pattern
            if (first == null)
                available.await();
            else {
                long delay = first.getDelay(NANOSECONDS);
                // 如果首节点已经超时,说明到了该任务的执行时间了,那么返回该任务
                if (delay <= 0)
                    return finishPoll(first);
                first = null; // don't retain ref while waiting
                // 如果leader不为空,说明有其他线程在执行任务,那么这里无限等待
                if (leader != null)
                    available.await();
                else {
                    // 否则,说明leader现在是空挡
                    Thread thisThread = Thread.currentThread();
                    // 将当前线程作为新的leader
                    leader = thisThread;
                    try {
                        // 等待任务
                        available.awaitNanos(delay);
                    } finally {
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
        if (leader == null && queue[0] != null)
            available.signal();
        lock.unlock();
    }
}

finishPoll

private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
    int s = --size;
    RunnableScheduledFuture<?> x = queue[s];
    queue[s] = null;
    if (s != 0)
        // 将最后节点放到堆顶,做堆下沉,重新整理二叉堆
        siftDown(0, x);
    setIndex(f, -1);
    return f;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容