面试厂家360,技术面三面。问题:你用过哪些线程池?请介绍一下。
我最常用的线程池是new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
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());
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 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工厂已经实现了适用于多个场景的线程池,而内部就是以上面的方式实现的。可惜我才疏学浅,尽然不知道。
由于使用了LinkedBlockingQueue
所以maximumPoolSize
没用,当corePoolSize
满了之后就加入到LinkedBlockingQueue
队列中。
每当某个线程执行完成之后就从LinkedBlockingQueue
队列中取一个。
所以这个是创建固定大小的线程池。
源码分析:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(
nThreads,
nThreads,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
创建线程数为1的线程池,由于使用了LinkedBlockingQueue
所以maximumPoolSize
没用,corePoolSize
为1表示线程数大小为1,满了就放入队列中,执行完了就从队列取一个。
源码分析
public static ExecutorService newSingleThreadExecutor() {
return new Executors.FinalizableDelegatedExecutorService
(
new ThreadPoolExecutor(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue())
);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
创建可缓冲的线程池。没有大小限制。由于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());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}