手写线程池

liujie7999 2019-09-24 02:55:14
需求背景:由于频繁的自行创建和销毁线程非常的消耗资 源,并且难以控制线程的并发数量,所以项目组急需编写 一个线程池功能,能够自行管理线程的生命周期,并且根 据繁忙线程池程度对池中线程进行动态扩容。
现在项目经理抽象出线程池对象中包含有几个主要特性 1. 可以根据任务数量进行线程数量扩容,在空闲时线程 池中只保存coreSize数量的线程,而当coreSize个线程已 经全部在工作时,这个时候如果再添加任务进来,会新建 线程,接受任务,直到池中的线程数量达到maxSize时, 不在新建线程 2. 当线程数量达到maxSize时,并且所有线程都处于工 作状态,这时如果还有任务添加过来,则将其保存在一个 队列中(可以自定义队列,也可以自行调研并使用jdk中已 有的Queue子类) 3. 如果队列中的任务数量已经达到了最大值(队列满 了),这个时候又有任务添加过来,则执行丢弃策略(可 以什么都不做,也可以仍出异常,也可以让主线程中直接 调用run处理掉等等,最好使用策略模式而不是if-else) 4. 定义线程的空闲时间,如果线程池处理完了任务,线 程空闲了,则根据已定义新增线程的空闲时间,如果时间
达到了,则回收线程直到线程数量达到coreSize数量为 止。(注意回收等操作的原子性,防止数据不一致)

思路,允许先在一个类中完成所有功能,再对代码进行面 向对象重构 也可以直接研读jdk线程池源码,参照写一份也可以(不建 议) 编写测试类,测试你的线程池是否功能正常
...全文
587 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
rumlee 2020-09-30
  • 打赏
  • 举报
回复
引用 17 楼 rumlee 的回复:
这种有现成的为啥要自己写,难道认为自己技术比oracle更牛X。
如果作为练习自己写没毛病,如果是作为商业项目,强烈建议不要自己写,不仅毫无价值,还可能带来不必要的麻烦。毕竟有成熟的而且经历过考验的东西肯定更好用一些。
rumlee 2020-09-30
  • 打赏
  • 举报
回复
这种有现成的为啥要自己写,难道认为自己技术比oracle更牛X。
softFE 2020-09-29
  • 打赏
  • 举报
回复
引用 7 楼 大隐藏于寺 的回复:
你的理解没啥问题,JDK的线程池java.util.concurrent.ThreadPoolExecutor的逻辑确实是如你所说的那样核心线程---队列---最大线程---拒绝策略.不过他们经理的设计思想与tomcat的线程池一致,tomcat的线程池的逻辑是核心线程---最大线程---队列----拒绝策略.关键源码可以看下org.apache.tomcat.util.threads.TaskQueue的offer()方法,如下,这里不展开讨论java.util.concurrent.ThreadPoolExecutor的execute()方法,感兴趣的同学自己去看下.

 @Override
    public boolean offer(Runnable o) {
      //we can't do any checks
        if (parent==null) return super.offer(o);
        //we are maxed out on threads, simply queue the object
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
        //we have idle threads, just add it to the queue
        if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
        //if we have less threads than maximum force creation of a new thread
        if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
        //if we reached here, we need to add it to the queue
        return super.offer(o);
    }
敬礼,受教了. //we are maxed out on threads, simply queue the object --> 线程耗尽了,放队列. //we have idle threads, just add it to the queue -->有空线程,放队列 怎么感觉怪怪的.
大隐藏于寺 2020-09-29
  • 打赏
  • 举报
回复
引用 10 楼 softFE 的回复:
[quote=引用 9 楼 大隐藏于寺 的回复:] 我解释下哈,代码里面的parent就是线程池org.apache.tomcat.util.threads.ThreadPoolExecutor,它继承了java.util.concurrent.ThreadPoolExecutor.

 //we are maxed out on threads, simply queue the object
  if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
这是在说池内线程数等于线程池初始化配置的最大线程数时,放队列,这个容易理解.说下后面这行代码,

 //we have idle threads, just add it to the queue
 if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
getSubmittedCount()方法获取的是线程池已提交的任务,包含队列中的和交给工作线程尚未完成的任务,而getPoolSize()获取到的是池中的线程,如果已提交的任务数<池中的线程数,说明有空闲线程可以直接从队列中获取任务,这时候就不用创建线程了.不知道这样解释清楚不
明白. 那这岂不是跟之前说的有冲突: 大于maxSize,放队列, 现在 任务数 < maxSize , 来了新任务, 不是应该直接调用线程去执行吗? 我是不是哪个地方理解的不到位...[/quote] 没有冲突. 1.当线程池中的线程数是maxPoolSize了,如果还有任务提交,将任务放进队列,目前可能有也可能没有空闲的线程,后面会有执行完任务的线程从队列取出任务来执行.

//we have idle threads, just add it to the queue
 if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
2.而上面这行代码说的是目前在线程池中就有空闲线程,它们阻塞在从队列获取任务的方法上,将任务放进队列里,会像你想的那样某个空闲线程会立即获取到任务并执行,估计你的盲点在于空闲线程怎么去执行后续提交的任务.如果提交任务时不判断线程池中是否有空闲线程,直接判断池中线程数是否小于maxPoolSize, 没有到maxPoolSize就新创建线程去执行任务的话,这会让线程池中空闲的线程空闲着,直到池中线程数达到了maxPoolSize,任务放进队列,这些空闲的下线程才能获取到任务执行,不能高效复用已存在的空闲线.这里需要结合java.util.concurrent.ThreadPoolExecutor的runWorker()和getTask()方法看下线程池中的线程是如何在执行完首个任务后去获取队列中的任务的.

 final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
  //task = getTask()是执行完首个任务后如何去获取任务的方法,注意这里是一个while循环,如果为task为null,当前线程不再执行新的任务,移除线程池
            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
                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);
        }
    }

 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.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

//如果timed为true,并且上一次循环中在指定时间内没有获取到任务,并且(池中线程数>1或者队列为空)返回null
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
 //这里是具体从队列获取任务的方法,根据timed判断使用获取任务的具体方法,如果使用take会一直阻塞到队列中有任务;
//如果使用poll()方法,那么会等待指定时间获取任务,到时间没有获取到任务返回null
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }


softFE 2020-09-29
  • 打赏
  • 举报
回复
引用 15 楼 大隐藏于寺 的回复:


//java.util.concurrent.ThreadPoolExecutor属性
 /**
     * Timeout in nanoseconds for idle threads waiting for work.
     * Threads use this timeout when there are more than corePoolSize
     * present or if allowCoreThreadTimeOut. Otherwise they wait
     * forever for new work.
     */
    private volatile long keepAliveTime;

    /**
     * If false (default), core threads stay alive even when idle.
     * If true, core threads use keepAliveTime to time out waiting
     * for work.
     */
    private volatile boolean allowCoreThreadTimeOut;
问题一回答: coreSize数量的线程不一定一直保持活动,可以通过java.util.concurrent.ThreadPoolExecutor的allowCoreThreadTimeOut属性设置(如上面的代码片段). 1.如果allowCoreThreadTimeOut为false,在没有任务的时候,coreSize数量的线程是处于java.lang.Thread.State: WAITING (parking)状态,不会被终止掉,池中一直保持最少coreSize数量的线程; 2.如果allowCoreThreadTimeOut为true时,所有线程可以空闲keepAliveTime时间,每次有线程超过这个时间没有获取到任务都会从池中终止掉一个线程(在我11楼回答中的getTask()方法有体现),终止的不一定是哪一个线程,总会终止一个线程,这里不展开源码去看了,贴出来有点多,可以说下因为超市终止一个线程的java.util.concurrent.ThreadPoolExecutor使用的关键方法名processWorkerExit(), tryTerminate(),interruptIdleWorkers(). 问题二回答: 回答之前我想说点概念上的区别,在现在的操作系统中,除开创建和终止,线程的状态有五个状态,分别是 (1) Ready (2) Running (3) Waiting (4) Delayed (5) Blocked 但是Java中线程的状态与这个有点区别,在java.lang.Thread.State中定义了六种状态(自己去看下源码,不贴出来,注释有点长),分别是 (1)TIMED_WAITING (2)NEW (3)RUNNABLE (4)BLOCKED (5)WAITING (6)TERMINATED 你说的就绪状态是指Java线程状态是Runable的么?处于Runable的线程不是空闲状态. 还是说处于WAITING状态,就像问题一中的回答?处于WAITING状态的线程是空闲状态. 还是说指的是操作系统中线程的Ready状态?Java线程Runable状态对应于操作系统线程的Ready和Running状态,处于操作系统的Ready状态的Java线程不是空闲状态.
damn it . 你知道的太多了. 膜拜~
softFE 2020-09-29
  • 打赏
  • 举报
回复
引用 9 楼 大隐藏于寺 的回复:
我解释下哈,代码里面的parent就是线程池org.apache.tomcat.util.threads.ThreadPoolExecutor,它继承了java.util.concurrent.ThreadPoolExecutor.

 //we are maxed out on threads, simply queue the object
  if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
这是在说池内线程数等于线程池初始化配置的最大线程数时,放队列,这个容易理解.说下后面这行代码,

 //we have idle threads, just add it to the queue
 if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
getSubmittedCount()方法获取的是线程池已提交的任务,包含队列中的和交给工作线程尚未完成的任务,而getPoolSize()获取到的是池中的线程,如果已提交的任务数<池中的线程数,说明有空闲线程可以直接从队列中获取任务,这时候就不用创建线程了.不知道这样解释清楚不
明白. 那这岂不是跟之前说的有冲突: 大于maxSize,放队列, 现在 任务数 < maxSize , 来了新任务, 不是应该直接调用线程去执行吗? 我是不是哪个地方理解的不到位...
大隐藏于寺 2020-09-29
  • 打赏
  • 举报
回复
引用 14 楼 softFE 的回复:
[quote=引用 13 楼 大隐藏于寺 的回复:] 前两条是正确的,最后一条总结得有点问题,是目前池中的没有空闲线程并且池中线程小于maxPoolSize时,来新任务了直接上新线程,之后就是重复这个判断过程.
coreSize 的线程 是一直会保持活跃吗? 他们没有任务的时候,是在就绪等待 还是销毁 . 如果是就绪这个时候他们算空闲吗. [/quote]


//java.util.concurrent.ThreadPoolExecutor属性
 /**
     * Timeout in nanoseconds for idle threads waiting for work.
     * Threads use this timeout when there are more than corePoolSize
     * present or if allowCoreThreadTimeOut. Otherwise they wait
     * forever for new work.
     */
    private volatile long keepAliveTime;

    /**
     * If false (default), core threads stay alive even when idle.
     * If true, core threads use keepAliveTime to time out waiting
     * for work.
     */
    private volatile boolean allowCoreThreadTimeOut;
问题一回答: coreSize数量的线程不一定一直保持活动,可以通过java.util.concurrent.ThreadPoolExecutor的allowCoreThreadTimeOut属性设置(如上面的代码片段). 1.如果allowCoreThreadTimeOut为false,在没有任务的时候,coreSize数量的线程是处于java.lang.Thread.State: WAITING (parking)状态,不会被终止掉,池中一直保持最少coreSize数量的线程; 2.如果allowCoreThreadTimeOut为true时,所有线程可以空闲keepAliveTime时间,每次有线程超过这个时间没有获取到任务都会从池中终止掉一个线程(在我11楼回答中的getTask()方法有体现),终止的不一定是哪一个线程,总会终止一个线程,这里不展开源码去看了,贴出来有点多,可以说下因为超市终止一个线程的java.util.concurrent.ThreadPoolExecutor使用的关键方法名processWorkerExit(), tryTerminate(),interruptIdleWorkers(). 问题二回答: 回答之前我想说点概念上的区别,在现在的操作系统中,除开创建和终止,线程的状态有五个状态,分别是 (1) Ready (2) Running (3) Waiting (4) Delayed (5) Blocked 但是Java中线程的状态与这个有点区别,在java.lang.Thread.State中定义了六种状态(自己去看下源码,不贴出来,注释有点长),分别是 (1)TIMED_WAITING (2)NEW (3)RUNNABLE (4)BLOCKED (5)WAITING (6)TERMINATED 你说的就绪状态是指Java线程状态是Runable的么?处于Runable的线程不是空闲状态. 还是说处于WAITING状态,就像问题一中的回答?处于WAITING状态的线程是空闲状态. 还是说指的是操作系统中线程的Ready状态?Java线程Runable状态对应于操作系统线程的Ready和Running状态,处于操作系统的Ready状态的Java线程不是空闲状态.
大隐藏于寺 2020-09-29
  • 打赏
  • 举报
回复
引用 8 楼 softFE 的回复:
[quote=引用 7 楼 大隐藏于寺 的回复:] 你的理解没啥问题,JDK的线程池java.util.concurrent.ThreadPoolExecutor的逻辑确实是如你所说的那样核心线程---队列---最大线程---拒绝策略.不过他们经理的设计思想与tomcat的线程池一致,tomcat的线程池的逻辑是核心线程---最大线程---队列----拒绝策略.关键源码可以看下org.apache.tomcat.util.threads.TaskQueue的offer()方法,如下,这里不展开讨论java.util.concurrent.ThreadPoolExecutor的execute()方法,感兴趣的同学自己去看下.

 @Override
    public boolean offer(Runnable o) {
      //we can't do any checks
        if (parent==null) return super.offer(o);
        //we are maxed out on threads, simply queue the object
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
        //we have idle threads, just add it to the queue
        if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
        //if we have less threads than maximum force creation of a new thread
        if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
        //if we reached here, we need to add it to the queue
        return super.offer(o);
    }
敬礼,受教了. //we are maxed out on threads, simply queue the object --> 线程耗尽了,放队列. //we have idle threads, just add it to the queue -->有空线程,放队列 怎么感觉怪怪的. [/quote] 我解释下哈,代码里面的parent就是线程池org.apache.tomcat.util.threads.ThreadPoolExecutor,它继承了java.util.concurrent.ThreadPoolExecutor.

 //we are maxed out on threads, simply queue the object
  if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
这是在说池内线程数等于线程池初始化配置的最大线程数时,放队列,这个容易理解.说下后面这行代码,

 //we have idle threads, just add it to the queue
 if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
getSubmittedCount()方法获取的是线程池已提交的任务,包含队列中的和交给工作线程尚未完成的任务,而getPoolSize()获取到的是池中的线程,如果已提交的任务数<池中的线程数,说明有空闲线程可以直接从队列中获取任务,这时候就不用创建线程了.不知道这样解释清楚不

   //org.apache.tomcat.util.threads.ThreadPoolExecutor中的属性


    /**
     * The number of tasks submitted but not yet finished. This includes tasks
     * in the queue and tasks that have been handed to a worker thread but the
     * latter did not start executing the task yet.
     * This number is always greater or equal to {@link #getActiveCount()}.
     */
    private final AtomicInteger submittedCount = new AtomicInteger(0);

softFE 2020-09-29
  • 打赏
  • 举报
回复
引用 13 楼 大隐藏于寺 的回复:
前两条是正确的,最后一条总结得有点问题,是目前池中的没有空闲线程并且池中线程小于maxPoolSize时,来新任务了直接上新线程,之后就是重复这个判断过程.
coreSize 的线程 是一直会保持活跃吗? 他们没有任务的时候,是在就绪等待 还是销毁 . 如果是就绪这个时候他们算空闲吗.
大隐藏于寺 2020-09-29
  • 打赏
  • 举报
回复
引用 12 楼 softFE 的回复:
[quote=引用 11 楼 大隐藏于寺 的回复:] 没有冲突. 1.当线程池中的线程数是maxPoolSize了,如果还有任务提交,将任务放进队列,目前可能有也可能没有空闲的线程,后面会有执行完任务的线程从队列取出任务来执行.

//we have idle threads, just add it to the queue
 if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
2.而上面这行代码说的是目前在线程池中就有空闲线程,它们阻塞在从队列获取任务的方法上,将任务放进队列里,会像你想的那样某个空闲线程会立即获取到任务并执行,估计你的盲点在于空闲线程怎么去执行后续提交的任务.如果提交任务时不判断线程池中是否有空闲线程,直接判断池中线程数是否小于maxPoolSize, 没有到maxPoolSize就新创建线程去执行任务的话,这会让线程池中空闲的线程空闲着,直到池中线程数达到了maxPoolSize,任务放进队列,这些空闲的下线程才能获取到任务执行,不能高效复用已存在的空闲线.这里需要结合java.util.concurrent.ThreadPoolExecutor的runWorker()和getTask()方法看下线程池中的线程是如何在执行完首个任务后去获取队列中的任务的.

 final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
  //task = getTask()是执行完首个任务后如何去获取任务的方法,注意这里是一个while循环,如果为task为null,当前线程不再执行新的任务,移除线程池
            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
                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);
        }
    }

 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.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

//如果timed为true,并且上一次循环中在指定时间内没有获取到任务,并且(池中线程数>1或者队列为空)返回null
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
 //这里是具体从队列获取任务的方法,根据timed判断使用获取任务的具体方法,如果使用take会一直阻塞到队列中有任务;
//如果使用poll()方法,那么会等待指定时间获取任务,到时间没有获取到任务返回null
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }


哦 明白了. 敬礼, 解释的很清楚. tomcat的线程池 : 线程数=maxSize ,将任务放入队列, 等线程慢慢获取. 任务数 < 线程数 ,将任务放入队列. 因为空闲线程都在队列那里等任务. 等线程池线程释放到只剩下coreSize, 再有任务来了,直接上线程处理,直到maxsize,放队列. 明白了. 多谢大佬. [/quote] 前两条是正确的,最后一条总结得有点问题,是目前池中的没有空闲线程并且池中线程小于maxPoolSize时,来新任务了直接上新线程,之后就是重复这个判断过程.
softFE 2020-09-29
  • 打赏
  • 举报
回复
引用 11 楼 大隐藏于寺 的回复:
没有冲突. 1.当线程池中的线程数是maxPoolSize了,如果还有任务提交,将任务放进队列,目前可能有也可能没有空闲的线程,后面会有执行完任务的线程从队列取出任务来执行.

//we have idle threads, just add it to the queue
 if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
2.而上面这行代码说的是目前在线程池中就有空闲线程,它们阻塞在从队列获取任务的方法上,将任务放进队列里,会像你想的那样某个空闲线程会立即获取到任务并执行,估计你的盲点在于空闲线程怎么去执行后续提交的任务.如果提交任务时不判断线程池中是否有空闲线程,直接判断池中线程数是否小于maxPoolSize, 没有到maxPoolSize就新创建线程去执行任务的话,这会让线程池中空闲的线程空闲着,直到池中线程数达到了maxPoolSize,任务放进队列,这些空闲的下线程才能获取到任务执行,不能高效复用已存在的空闲线.这里需要结合java.util.concurrent.ThreadPoolExecutor的runWorker()和getTask()方法看下线程池中的线程是如何在执行完首个任务后去获取队列中的任务的.

 final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
  //task = getTask()是执行完首个任务后如何去获取任务的方法,注意这里是一个while循环,如果为task为null,当前线程不再执行新的任务,移除线程池
            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
                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);
        }
    }

 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.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

//如果timed为true,并且上一次循环中在指定时间内没有获取到任务,并且(池中线程数>1或者队列为空)返回null
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
 //这里是具体从队列获取任务的方法,根据timed判断使用获取任务的具体方法,如果使用take会一直阻塞到队列中有任务;
//如果使用poll()方法,那么会等待指定时间获取任务,到时间没有获取到任务返回null
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }


哦 明白了. 敬礼, 解释的很清楚. tomcat的线程池 : 线程数=maxSize ,将任务放入队列, 等线程慢慢获取. 任务数 < 线程数 ,将任务放入队列. 因为空闲线程都在队列那里等任务. 等线程池线程释放到只剩下coreSize, 再有任务来了,直接上线程处理,直到maxsize,放队列. 明白了. 多谢大佬.
大隐藏于寺 2020-09-28
  • 打赏
  • 举报
回复
引用 6 楼 softFE 的回复:
, 线程池 原本的设计是 任务数量超过 coreSize,放队列, 任务队列放满之后 ,再有任务开始新建线程执行, 除非线程数目已经达到 maxSize . 之后就执行 拒绝策略. 我俩到底谁错了. 还是你们经理的设计 就喜欢 违反 原本的设计来.
你的理解没啥问题,JDK的线程池java.util.concurrent.ThreadPoolExecutor的逻辑确实是如你所说的那样核心线程---队列---最大线程---拒绝策略.不过他们经理的设计思想与tomcat的线程池一致,tomcat的线程池的逻辑是核心线程---最大线程---队列----拒绝策略.关键源码可以看下org.apache.tomcat.util.threads.TaskQueue的offer()方法,如下,这里不展开讨论java.util.concurrent.ThreadPoolExecutor的execute()方法,感兴趣的同学自己去看下.

 @Override
    public boolean offer(Runnable o) {
      //we can't do any checks
        if (parent==null) return super.offer(o);
        //we are maxed out on threads, simply queue the object
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
        //we have idle threads, just add it to the queue
        if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
        //if we have less threads than maximum force creation of a new thread
        if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
        //if we reached here, we need to add it to the queue
        return super.offer(o);
    }
softFE 2020-09-28
  • 打赏
  • 举报
回复
, 线程池 原本的设计是 任务数量超过 coreSize,放队列, 任务队列放满之后 ,再有任务开始新建线程执行, 除非线程数目已经达到 maxSize . 之后就执行 拒绝策略. 我俩到底谁错了. 还是你们经理的设计 就喜欢 违反 原本的设计来.
liujie7999 2019-09-25
  • 打赏
  • 举报
回复
引用 3 楼 YangCheney的回复:
建议你查看一下当前主流技术的源码, 先这样,然后这样,然后再这样就行了。
我理解了,我试了一下那样子,然后这样子敲了一下,最后那样子成功了
OxYGC 2019-09-25
  • 打赏
  • 举报
回复
建议你查看一下当前主流技术的源码, 先这样,然后这样,然后再这样就行了。
瘦死的黑骆驼 2019-09-25
  • 打赏
  • 举报
回复
引用 4 楼 ^@独狼@^ 的回复:
[quote=引用 3 楼 YangCheney的回复:]建议你查看一下当前主流技术的源码, 先这样,然后这样,然后再这样就行了。
我理解了,我试了一下那样子,然后这样子敲了一下,最后那样子成功了[/quote] 这回答666
向上啊-up 2019-09-24
  • 打赏
  • 举报
回复
你可以看看jdk源码,然后在这样那样就行
瘦死的黑骆驼 2019-09-24
  • 打赏
  • 举报
回复
自己手写太费时了吧,ExecutorService threadPool = Executors.newCachedThreadPool()可以了解下。和你的需求有些类似

62,628

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧