Java并发编程一线程池简介
为什么我们需要使用线程池?
我们知道线程是一种比较昂贵的资源,我们通过程序每创建一个线程去执行,其实操作系统都会对应地创建一个线程去执行我们的任务,而我们频繁的创建、销毁线程是非常耗费系统资源的,当并发数不大时,对系统似乎没什么影响,但当并发数很大时,我们为每一个请求都去创建一个线程,然后等待被调度、执行完任务后再销毁,这样频繁的创建、销毁线程是很耗费系统资源的。
而我们使用线程池去管理线程,就可以很好的减少这种损耗,因为线程池会复用线程,什么是复用线程呢?就是线程池里面的线程,并不和我们自己创建一个线程去执行单个任务一样,执行完这个任务线程就结束了,而线程池中的线程,它的执行逻辑中有一个while
循环,在这个while
循环中,线程会不断的去获取任务,然后执行(有任务的情况下),如果在高并发环境下,这会极大的减少线程的创建与销毁操作,节约系统的资源。
我们来看一看线程池的部分源码:
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
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);
}
}
Repeatedly gets tasks from queue and executes them
这是上面这个方法的一段注释,从方法的代码和注释中,都很明显的展现了线程池中的线程并不是执行完一个任务就结束了,而是会主动(重复)去获取任务,然后执行。
线程池的设计
很明显是面向接口编程。
线程池的一些属性
下面是这些属性的源码与注释,结合上图应该不难看懂。
/**
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
*/
private volatile int corePoolSize;
/**
* Maximum pool size. Note that the actual maximum is internally
* bounded by CAPACITY.
*/
private volatile int maximumPoolSize;
/**
* 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;
/**
* The queue used for holding tasks and handing off to worker
* threads. We do not require that workQueue.poll() returning
* null necessarily means that workQueue.isEmpty(), so rely
* solely on isEmpty to see if the queue is empty (which we must
* do for example when deciding whether to transition from
* SHUTDOWN to TIDYING). This accommodates special-purpose
* queues such as DelayQueues for which poll() is allowed to
* return null even if it may later return non-null when delays
* expire.
*/
private final BlockingQueue<Runnable> workQueue;
/**
* Factory for new threads. All threads are created using this
* factory (via method addWorker). All callers must be prepared
* for addWorker to fail, which may reflect a system or user's
* policy limiting the number of threads. Even though it is not
* treated as an error, failure to create threads may result in
* new tasks being rejected or existing ones remaining stuck in
* the queue.
*
* We go further and preserve pool invariants even in the face of
* errors such as OutOfMemoryError, that might be thrown while
* trying to create threads. Such errors are rather common due to
* the need to allocate a native stack in Thread.start, and users
* will want to perform clean pool shutdown to clean up. There
* will likely be enough memory available for the cleanup code to
* complete without encountering yet another OutOfMemoryError.
*/
private volatile ThreadFactory threadFactory;
/**
* Handler called when saturated or shutdown in execute.
*/
private volatile RejectedExecutionHandler handler;
线程池结构
线程池创建线程
这个图是中文的,应该很生动了,就不需要解释了吧。
线程池拒绝任务
当线程池的任务队列满了,并且无法再创建新的线程了(线程数量达到maximumPoolSize
),线程池就会拒绝任务。其实还有其他情况线程池也会拒绝任务,这里只是简单让大家知道,线程池是会拒绝任务的。
这里只是让大家对Java线程池有一个大概的了解,并没有详细讲解原理,毕竟博主也是初学者,以后有机会会再进行补充的。