線程池 詳解 吐血整理
數哥:你們用多線程嗎?
我:用啊
數哥:我們根本不需要,厲害吧
我:。。。。。。厲害
數哥:你們怎麼用的啊?
我:一般都是用線程池,不會直接創建線程
數哥:線程池??? 幹什麼的?
我:。。。。。。 !!!!!!
1、使用線程池的好處
-
我們知道創建
-
減少了創建和銷燬線程的次數,每個工作線程都可以被重複利用,可執行多個任務。
-
可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因爲消耗過多的內存,而把服務器累趴下
2、線程池創建、執行
2.1線程池的執行流程
2.2線程池創建及使用
2.2.1task源碼
class Task implements Callable {
private int num1;
private int num2;
public Task(){}
public Task(int num1,int num2){
this.num1=num1;
this.num2=num2;
}
@Override
public Integer call() throws Exception {
int sum=0;
for(int i=num1;i<=num2;i++){
sum+=i;
}
return sum;
}
}
2.2.2線程池使用
/**
* 計算 400 數 和
* 使用線程池
*/
@Test
public void pooltest() throws ExecutionException, InterruptedException {
int corePoolSize = 4;
int maximumPoolSize = 4;
long keepAliveTime = 1000;
TimeUnit unit = TimeUnit.MICROSECONDS;
BlockingQueue a = new SynchronousQueue();
// ArrayBlockingQueue DelayQueue LinkedBlockingQueue PriorityBlockingQueue
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
創建線程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, a, threadFactory, handler);
// 創建 任務
Task t1=new Task(1,100);
Task t2=new Task(101,200);
Task t3=new Task(201,300);
Task t4=new Task(301,400);
// 讓線程池自主選擇一條線程執行線程任務
Future<Integer> f1=threadPoolExecutor.submit(t1);
Future<Integer> f2=threadPoolExecutor.submit(t2);
Future<Integer> f3=threadPoolExecutor.submit(t3);
Future<Integer> f4=threadPoolExecutor.submit(t4);
threadPoolExecutor.shutdown();
int sum1=f1.get();
int sum2=f2.get();
int sum3=f3.get();
int sum4=f4.get();
System.out.println(sum1+sum2+sum3+sum4);
}
3、線程池各參數 詳解
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param corePoolSize 是一直存活在線程池中的線程數,即使這些線程被閒置,除非設置參數
* {@code allowCoreThreadTimeOut}
*
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param maximumPoolSize 在線程池中能存活的 最大線程數
*
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param keepAliveTime 如果線程池中的 線程數比 核心線程數(corePoolSize)大
* 此參數是 閒置線程 等待新任務執行的 最長 時間
*
* @param unit the time unit for the {@code keepAliveTime} argument
* @param unit {@code keepAliveTime} 參數的 時間單位
*
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param workQueue 此隊列用於存儲未執行的任務(任務實現了Runnable接口,並且通過excute方法提交)
*
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param threadFactory 線程池用來創建線程的 工廠
*
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @param handler 處理 因爲達到了線程邊界和隊列容量而導致 執行阻塞的 策略
*
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
3.1阻塞隊列:BlockingQueue
ArrayBlockingQueue`,
`DelayQueue`,
`LinkedBlockingDeque`,
`LinkedBlockingQueue`,
`LinkedTransferQueue`,
`PriorityBlockingQueue`,
`SynchronousQueue
3.1.1無界隊列
隊列大小無限制,常用的爲無界的LinkedBlockingQueue,使用該隊列做爲阻塞隊列時要尤其當心,當任務耗時較長時可能會導致大量新任務在隊列中堆積最終導致OOM。當QPS很高,發送數據很大,大量的任務被添加到這個無界LinkedBlockingQueue 中,導致內存飆升服務器掛掉。
3.1.2有界隊列
常用的有兩類,一類是遵循FIFO原則的隊列如ArrayBlockingQueue,另一類是優先級隊列如PriorityBlockingQueue。PriorityBlockingQueue中的優先級由任務的Comparator決定。
使用有界隊列時隊列大小需和線程池大小互相配合,線程池較小有界隊列較大時可減少內存消耗,降低cpu使用率和上下文切換,但是可能會限制系統吞吐量。
3.1.3同步移交隊列
如果不希望任務在隊列中等待而是希望將任務直接移交給工作線程,可使用SynchronousQueue作爲等待隊列。SynchronousQueue不是一個真正的隊列,而是一種線程之間移交的機制。要將一個元素放入SynchronousQueue中,必須有另一個線程正在等待接收這個元素。只有在使用無界線程池或者有飽和策略時才建議使用該隊列。
3.2飽和策略
3.2.1ThreadPoolExecutor.AbortPolicy
描述
直接拋異常,不處理
源碼
/**
* A handler for rejected tasks that throws a
* {@link RejectedExecutionException}.
*
* This is the default handler for {@link ThreadPoolExecutor} and
* {@link ScheduledThreadPoolExecutor}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
3.2.2ThreadPoolExecutor.CallerRunsPolicy
描述
它直接在{@code execute}方法的調用線程中運行被拒絕的任務,除非執行程序已經關閉,在這種情況下任務將被丟棄
源碼
/**
* A handler for rejected tasks that runs the rejected task
* directly in the calling thread of the {@code execute} method,
* unless the executor has been shut down, in which case the task
* is discarded.
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
3.2.3ThreadPoolExecutor.DiscardOldestPolicy
描述
丟棄隊列最前面的任務,然後重新嘗試執行任務(不適合工作隊列爲優先隊列場景)
源碼
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
3.2.4ThreadPoolExecutor.DiscardPolicy
描述
新提交的任務被拋棄,但是不拋出異常
源碼
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
4、JDK提供線程池
4.1Executors.newScheduledThreadPool
/**
* Creates a thread pool that can schedule commands to run after a
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
* @param threadFactory the factory to use when the executor
* creates a new thread
* @return the newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* @throws NullPointerException if threadFactory is null
*/
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
--------------------------------------------------------------------------------------------------
/**
* Creates a new {@code ScheduledThreadPoolExecutor} with the
* given initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param threadFactory the factory to use when the executor
* creates a new thread
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* @throws NullPointerException if {@code threadFactory} is null
*/
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory);
}
4.2Executors.newCachedThreadPool
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available, and uses the provided
* ThreadFactory to create new threads when needed.
*
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
*/
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
4.3Executors.newFixedThreadPool
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue, using the provided
* ThreadFactory to create new threads when needed. At any point,
* at most {@code nThreads} threads will be active processing
* tasks. If additional tasks are submitted when all threads are
* active, they will wait in the queue until a thread is
* available. If any thread terminates due to a failure during
* execution prior to shutdown, a new one will take its place if
* needed to execute subsequent tasks. The threads in the pool will
* exist until it is explicitly {@link ExecutorService#shutdown
* shutdown}.
*
* @param nThreads the number of threads in the pool
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
4.4Executors.newSingleThreadExecutor
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue, and uses the provided ThreadFactory to
* create a new thread when needed. Unlike the otherwise
* equivalent {@code newFixedThreadPool(1, threadFactory)} the
* returned executor is guaranteed not to be reconfigurable to use
* additional threads.
*
* @param threadFactory the factory to use when creating new threads
* @return the newly created single-threaded Executor
* @throws NullPointerException if threadFactory is null
*/
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
4.5Executors.newSingleThreadScheduledExecutor
/**
* Creates a single-threaded executor that can schedule commands
* to run after a given delay, or to execute periodically. (Note
* however that if this single thread terminates due to a failure
* during execution prior to shutdown, a new one will take its
* place if needed to execute subsequent tasks.) Tasks are
* guaranteed to execute sequentially, and no more than one task
* will be active at any given time. Unlike the otherwise
* equivalent {@code newScheduledThreadPool(1, threadFactory)}
* the returned executor is guaranteed not to be reconfigurable to
* use additional threads.
*
* @param threadFactory the factory to use when creating new threads
* @return the newly created scheduled executor
* @throws NullPointerException if threadFactory is null
*/
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1, threadFactory));
}
4.6Executors.newWorkStealingPool
/**
* Creates a thread pool that maintains enough threads to support
* the given parallelism level, and may use multiple queues to
* reduce contention. The parallelism level corresponds to the
* maximum number of threads actively engaged in, or available to
* engage in, task processing. The actual number of threads may
* grow and shrink dynamically. A work-stealing pool makes no
* guarantees about the order in which submitted tasks are
* executed.
*
* @param parallelism the targeted parallelism level
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code parallelism <= 0}
* @since 1.8
*/
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
/**
* Creates a work-stealing thread pool using the number of
* {@linkplain Runtime#availableProcessors available processors}
* as its target parallelism level.
*
* @return the newly created thread pool
* @see #newWorkStealingPool(int)
* @since 1.8
*/
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
Alibaba 編碼規約
一 -(六)- 4
【強制】 線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這
樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。
說明: Executors 返回的線程池對象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:
允許的請求隊列長度爲 Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM。
2) CachedThreadPool:
允許的創建線程數量爲 Integer.MAX_VALUE, 可能會創建大量的線程,從而導致 OOM。
如有問題,歡迎大家留言指正,會虛心接納,補充學習
請大家,點贊 收藏,謝謝