面試廠家360,技術面三面。問題:你用過哪些線程池?請介紹一下。
我最常用的線程池是new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) ,以下就是我最常用的線程池代碼,我也向面試官簡單介紹了我的用法,但答案不是面試官想要的。直接上代碼:
ThreadPoolExecutorTest.java
package com.bds.lww.demo.thread;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author liuww 2019/12/19
*/
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
// 創建一個線程的線程池
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
for (int i = 0; i < 10; i++) {
pool.execute(new ThreadPoolTask(i));
}
try {
//等待所有線程執行完畢當前任務。
pool.shutdown();
boolean loop = true;
do {
//等待所有線程執行完畢當前任務結束
loop = !pool.awaitTermination(2, TimeUnit.SECONDS);//等待2秒
} while (loop);
if (loop != true) {
System.out.println("所有線程執行完畢");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("耗時:" + (System.currentTimeMillis() - System.currentTimeMillis()));
}
}
}
ThreadPoolTask.java
package com.bds.lww.demo.thread;
/**
* @author liuww 2019/12/19
*/
public class ThreadPoolTask implements Runnable {
private Object attachData;
ThreadPoolTask(Object tasks) {
this.attachData = tasks;
}
@Override
public void run() {
try {
System.out.println("開始執行任務:" + attachData + "任務,使用的線程池,線程名稱:" + Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
attachData = null;
}
}
執行結果:
開始執行任務:1任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:3任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:4任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:5任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:6任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:7任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:8任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:9任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:0任務,使用的線程池,線程名稱:pool-1-thread-1
開始執行任務:2任務,使用的線程池,線程名稱:pool-1-thread-3
所有線程執行完畢
耗時:0
源碼分析 ,ThreadPoolExecutor
的構造函數
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;
}
其實java的Executors工廠已經實現了適用於多個場景的線程池,而內部就是以上面的方式實現的。可惜我才疏學淺,盡然不知道。
1.newFixedThreadPool()
由於使用了LinkedBlockingQueue
所以maximumPoolSize
沒用,當corePoolSize
滿了之後就加入到LinkedBlockingQueue
隊列中。
每當某個線程執行完成之後就從LinkedBlockingQueue
隊列中取一個。
所以這個是創建固定大小的線程池。
源碼分析:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(
nThreads,
nThreads,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2.newSingleThreadPool()
創建線程數爲1的線程池,由於使用了LinkedBlockingQueue
所以maximumPoolSize
沒用,corePoolSize
爲1表示線程數大小爲1,滿了就放入隊列中,執行完了就從隊列取一個。
源碼分析
public static ExecutorService newSingleThreadExecutor() {
return new Executors.FinalizableDelegatedExecutorService
(
new ThreadPoolExecutor(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>())
);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
3.newCachedThreadPool()
創建可緩衝的線程池。沒有大小限制。由於corePoolSize
爲0所以任務會放入SynchronousQueue
隊列中,SynchronousQueue
只能存放大小爲1,所以會立刻新起線程,由於maxumumPoolSize
爲Integer.MAX_VALUE
所以可以認爲大小爲2147483647
。受內存大小限制。
源碼分析
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(
0,
Integer.MAX_VALUE,
60L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}