/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory and rejected execution handler.
* It may be more convenient to use one of the {@link Executors} factory
* methods instead of this general purpose constructor.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @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 unit the time unit for the {@code keepAliveTime} argument
* @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.
* @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} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
簡單介紹下參數含義:如果運行的線程少於corePoolSize,則 Executor始終首選添加新的線程,而不進行排隊。(如果當前運行的線程小於corePoolSize,則任務根本不會存入queue中,而是直接運行)
如果運行的線程大於等於 corePoolSize,則 Executor始終首選將請求加入隊列,而不添加新的線程。
如果無法將請求加入隊列,則創建新的線程,除非創建此線程超出 maximumPoolSize,在這種情況下,任務將被拒絕。
主要有3種類型的BlockingQueue:
使用有界隊列時隊列大小需和線程池大小互相配合,線程池較小有界隊列較大時可減少內存消耗,降低cpu使用率和上下文切換,但是可能會限制系統吞吐量。
如果不希望任務在隊列中等待而是希望將任務直接移交給工作線程,可使用SynchronousQueue作爲等待隊列。SynchronousQueue不是一個真正的隊列,而是一種線程之間移交的機制。要將一個元素放入SynchronousQueue中,必須有另一個線程正在等待接收這個元素。只有在使用無界線程池或者有飽和策略時才建議使用該隊列。
創建線程池的5種方式(jdk1.8之後加了一種)
public class Test {
public static void main(String[] args) {
//1.創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
int index = i;
try {
Thread.sleep(i * 500);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("index: " + index);
}
});
}
//2.創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
int index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println("index: " + index);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
//3.創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
//4.創建一個定長線程池,支持定時及週期性任務執行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(0);
// 第二個參數代表:初始延時多久
// 第三個參數代表:週期的間隔
// 第四個參數代表:時間的單位
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
scheduledThreadPool.shutdown();
//5.newWorkStealingPool創建一個擁有多個任務隊列(以便減少連接數)的線程池
//1.8的新特性
ExecutorService newWorkStealingPool = Executors.newWorkStealingPool();
List<Callable<String>> callables = Arrays.asList(
callable("task1", 1),
callable("task2", 2),
callable("task3", 3));
try {
//單個執行線程
String result = newWorkStealingPool.invokeAny(callables);
System.out.println(result);
//執行全部
List<Future<String>> all = newWorkStealingPool.invokeAll(callables);
//future是一個接口,有幾個方法:boolean cancel(boolean mayInterruptIfRunning);
//boolean isCancelled();
//boolean isDone();
//V get() throws InterruptedException, ExecutionException;
//V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
for (Future<String> future : all) {
String f = future.get();
System.out.println(f);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static Callable<String> callable(String result, long sleepSeconds) {
return () -> {
TimeUnit.SECONDS.sleep(sleepSeconds);
return result;
};
}
}