62,628
社区成员
发帖
与我相关
我的任务
分享
//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;
}
}
}
//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线程不是空闲状态.
//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);
@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);
}
