java線程池實現
線程池是一種多線程處理形式,處理過程中將任務添加到隊列,然後在創建線程後自動啓動這些任務。
五種Java線程池功能及分析
線程池都繼承了ExecutorService的接口
因爲繼承了ExecutorService接口,ExecutorService是Java提供的用於管理線程池的類。
該類的兩個作用:控制線程數量和重用線程。
只有調用了shutdown()的時候纔是正式的終止了這個線程池。
四種常見的線程池詳解
java通過Executors工廠類提供我們的線程池一共有4種:
Executors.newFixedThreadPool(int n)
//啓動固定線程數的線程池
Executors.newCacheThreadPool()
//按需分配的線程池
Executors.newScheduledThreadPool(int n)
//定時,定期執行任務的線程池
Executors.newSingleThreadExecutor()
://單線程化的線程池。
一、單線程化的線程池newSingleThreadExecutor
串行執行所有任務
/**
* 單線程化的線程池
* 串行執行所有任務
*/
public void singleThreadPool() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
Future<Integer> task = executorService.submit(() -> {
Thread.currentThread().setName("Thread i = " + index);
System.out.println("執行單線程化的線程池:" + Thread.currentThread().getName());
return 50;
});
System.out.println("第" + i + "次計算,結果:" + task.get());
}
//銷燬線程池
executorService.shutdown();
}
二、固定線程數的線程池newFixedThreadPool
fixedThreadPool(int size) 就只有一個參數,size,就是線程池中最大可創建多少個線程。
如下:創建2個線程的fixedThreadPool ,當2個都爲活躍的時候,後面的任務會被加入無邊界的鏈式隊列,有空閒,就執行任務。
/**
* 啓動固定線程數的線程池
*
* @param size 線程池中最大可創建多少個線程
* @throws ExecutionException 執行異常
* @throws InterruptedException 中斷異常
*/
public void fixedThreadPool(int size) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(size);
for (int i = 0; i < 10; i++) {
Future<Integer> task = executorService.submit(() -> {
System.out.println("執行線程" + Thread.currentThread().getName());
return 40;
});
System.out.println("第" + i + "次計算,結果:" + task.get());
}
//銷燬線程池
executorService.shutdown();
}
三、按需分配的線程池newCacheThreadPool
CachedThreadPool比fixedThreadPool更快,只要有任務並且其他線程都在活躍態,就會開啓一個新的線程。最大線程數:Integer.MAX_VALUE = 0x7fffffff
/**
* 按需分配的線程池
* CachedThreadPool比fixedThreadPool更快
* 只要有任務並且其他線程都在活躍態,就會開啓一個新的線程
* 最大線程數:Integer.MAX_VALUE = 0x7fffffff
*/
public void cacheThreadPool() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
Future<Integer> task = executorService.submit(() -> {
System.out.println("執行線程" + Thread.currentThread().getName());
return 50;
});
System.out.println("第" + i + "次計算,結果:" + task.get());
}
//銷燬線程池
executorService.shutdown();
}
四、定時執行的線程池newScheduledThreadPool
newScheduledThreadPool有schedule和scheduleAtFixedRate方法用來做定時任務,scheduleAtFixedRate多了一個週期的參數period。
schedule(Runnable command,long delay, TimeUnit unit)
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
代碼如下:
/**
* 定時定期的線程池
*/
public void scheduledThreadPool() {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
//延遲3s後運行
for (int i = 0; i < 10; i++) {
scheduledThreadPool.schedule(() ->
System.out.println("執行線程" + Thread.currentThread().getName()), 10, TimeUnit.SECONDS);
}
// scheduledThreadPool.scheduleAtFixedRate(() ->
// System.out.println("scheduleAtFixedRate:執行線程" + Thread.currentThread().getName()), 1,1, TimeUnit.SECONDS);
//銷燬線程池
scheduledThreadPool.shutdown();
}
自定義線程池newFixedThreadPool
ThreadPoolExecutor()//指定線程數的線程池。
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
自定義線程池,可以用ThreadPoolExecutor類創建,它有多個構造方法來創建線程池。
corePoolSize
核心線程池大小
maximumPoolSize
最大線程池大小----30
keepAliveTime
線程池中超過corePoolSize數目的空閒線程最大存活時間
TimeUnit
keepAliveTime時間單位----TimeUnit.MINUTES
workQueue
阻塞隊列
threadFactory
新建線程工廠
rejectedExecutionHandler
當提交任務數超過maxmumPoolSize+workQueue之和時, 任務會交給RejectedExecutionHandler來處理。
提交任務
可以向ThreadPoolExecutor提交兩種任務:Callable和Runnable。
-
Callable
該類任務有返回結果,可以拋出異常。
通過submit函數提交,返回Future對象。
可通過get獲取執行結果。 -
Runnable
該類任務只執行,無法獲取返回結果,並在執行過程中無法拋異常。
通過execute提交。
關閉線程池
關閉線程池有兩種方式:shutdown和shutdownNow,關閉時,會遍歷所有的線程,調用它們的interrupt函數中斷線程。但這兩種方式對於正在執行的線程處理方式不同。
-
shutdown()
僅停止阻塞隊列中等待的線程,那些正在執行的線程就會讓他們執行結束。
-
shutdownNow()
不僅會停止阻塞隊列中的線程,而且會停止正在執行的線程。
最大線程數一般設爲2N+1最好,N是CPU核數
public static void main(String[] args) {
CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();
//1. 初始化
exec.init();
ExecutorService executorService = exec.getCustomThreadPoolExecutor();
for (int i = 0; i < 100; i++) {
System.out.println("提交第" + i + "個任務");
executorService.execute(() -> {
try {
System.out.println("執行自定義的線程池:" + Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
try {
//銷燬
Thread.sleep(1000);
exec.destory();
} catch (InterruptedException e) {
e.printStackTrace();
}
}