推薦:Java并發程式設計彙總
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
),線程池就會拒絕任務。其實還有其他情況線程池也會拒絕任務,這裡隻是簡單讓大家知道,線程池是會拒絕任務的。