線程池
JDK1.8官方介紹:
Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each ThreadPoolExecutor also maintains some basic statistics, such as the number of completed tasks.
線程池解決了兩個問題:它們通常在執行大量異步任務時提供改進性能問題,由於減少了每個任務的資源開銷,他們提供邊界和管理資源的手段,包括線程,消費在執行任務的集合。每個ThreadPoolExecutor 維持一些基本的統計數據,比如完成任務數量。
線程池的原理
- 線程池本身是不創建和啓動線程的,只有任務到達時纔會,即當一個任務提交到線程池時,就會創建一個線程。但可以重寫動態使用方法prestartCoreThread()或prestartCoreAllThread()。
- 當線程數沒有達到核心線程數corePoolSize時,就會創建一個新的線程,不需要排隊。當線程數大於核心線程數corePoolSize時,就會放到workerQueue任務隊列裏等待。
- 當核心線程數小於等於線程總數maximunPoolSize時,如果隊列中有等待的線程,則線程池會用空餘的線程來執行隊列的線程;否則,線程池就會採用拒絕策略來終止新的任務。
- 如果某個線程會話時間超出保持會話時間keepAliveTime時,就會終止當前線程任務,然後加入新的線程任務。可以使用setKeepAliveTime(long, java.util.concurrent.TimeUnit)動態改變參數。一般來說,這個活動策略是已經超出了corePoolSize的線程時才應用。但只要keepAliveTime非0時,就可以通過allowCoreThreadTimeOut(true)方法,使超時策略應用在覈心線程中。
任務排隊
-直接提交:工作隊列WorkQueue默認是SychronousQueue。它繼承了AbstractQueue,實現了BlockingQueue。他的處理任務容量是無邊界的。
當運行的線程數大於或等於核心線程corePoolSize時,纔會加入隊列,但直接提交是同步阻塞的。從下圖的工作原理可以看出,直接提交maximunPoolSize最好無限大即無容量大小。
/**
- Creates a {@code SynchronousQueue} with nonfair access policy.
*/
public SynchronousQueue() {
this(false);
}
/**
- Creates a {@code SynchronousQueue} with the specified fairness policy.
*
- @param fair if true, waiting threads contend in FIFO order for
- access; otherwise the order is unspecified.
*/
public SynchronousQueue(boolean fair) { //fair 公平性標識
// 公平性TrasferQueue、 非公平行TransferStack
transferer = fair ? new TransferQueue() : new TransferStack();
}
線程池類:ThreadPoolExecutor
應用場景:交換任工作,生產者的線程消費和消費者的線程同步傳遞消息、時間或任務。簡單的說,任務2必須依賴於任務1的信息,
-無界隊列:LinkedBlockingQueue。它保證所有的超出corePoolSize的線程都放入隊列裏。這樣創建的線程不會超出corePoolSize.,因此maximumPoolSize值就無效了。
線程池類:newFixedThreadPool
- Creates a {@code LinkedBlockingQueue} with a capacity of
- {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
/**
- Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
*
- @param capacity the capacity of this queue
- @throws IllegalArgumentException if {@code capacity} is not greater
- than zero
*/
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node(null);
}
/**
- Creates a {@code LinkedBlockingQueue} with a capacity of
- {@link Integer#MAX_VALUE}, initially containing the elements of the
- given collection,
- added in traversal order of the collection's iterator.
*
- @param c the collection of elements to initially contain
- @throws NullPointerException if the specified collection or any
- of its elements are null
*/
public LinkedBlockingQueue(Collection c) {
this(Integer.MAX_VALUE);
final ReentrantLock putLock = this.putLock;
putLock.lock(); // Never contended, but necessary for visibility
try {
int n = 0;
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (n == capacity)
throw new IllegalStateException("Queue full");
enqueue(new Node(e));
++n;
}
count.set(n);
} finally {
putLock.unlock();
}
}
應用場景:適合任務之間互不影響
-有界隊列:ArrayBlockingQueue。這是最複雜的一種。不推薦使用。當使用有限的MaximumPoolSize時,有界隊列可以防止資源耗盡,但可能很難控制與調整。隊列的容量是有限的。
一般使用大池小列或小池大列,前者會增加CPU使用率,但遇到不可接受的調度開銷,也會降低吞吐量;後者會減少CPU使用率、操作系統資源和上下文的切換,但可能導致人工來降低吞吐量。
/**
- Creates an {@code ArrayBlockingQueue} with the given (fixed)
- capacity and default access policy.
*
- @param capacity the capacity of this queue
- @throws IllegalArgumentException if {@code capacity < 1}
*/
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
/**
- Creates an {@code ArrayBlockingQueue} with the given (fixed)
- capacity and the specified access policy.
*
- @param capacity the capacity of this queue
- @param fair if {@code true} then queue accesses for threads blocked
- on insertion or removal, are processed in FIFO order;
- if {@code false} the access order is unspecified.
- @throws IllegalArgumentException if {@code capacity < 1}
*/
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
public ArrayBlockingQueue(int capacity, boolean fair,
Collection c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
從上可以看出:有界隊列ArrayBlockingQueue和無界隊列LinkedBlockingQueue都是使用ReentrantLock重入鎖,而同步隊列sychoronousQueue是使用公平性TransferQueue和非共性TransferStack,即轉移數據隊列和轉移數據棧,從數據結構便知數據的順序。