什么是线程池
在日常的开发中,使用多线程处理一些并发任务的需求经常会见到,为了避免重复的创建和销毁线程,我们可以使用线程池达到线程复用的目的。当需要线程时,从线程池中获取一个空闲的线程;当完成工作时,将线程归还到线程池中。
JDK对线程池的实现
以上成员均在java.util.concurrent包中。
ThreadPoolExecutor表示一个线程池。
Executor框架提供的方法如下
newFixedThreadPool()
该方法返回一个固定数量的线程池,线程池中的线程数量不变。当有新任务提交,若线程池中有空闲线程,任务会立即执行;若没有空闲线程,会将任务放到队列中,待有空闲线程的时候,再执行。
newSingleThreadExecutor()
该方法返回只有一个线程的线程池,若多余一个任务提交到线程池,任务会被暂存到一个队列中。线程空闲时,从队列中按照先入先出的顺序执行队列中的任务。
newCachedThreadPool()
该方法返回一个可以根据实际情况进行调整的线程池。若线程池中的所有线程都在工作,这时又有新的任务提交,则会创建新的线程进行执行任务。所有线程处理完成任务后,返回线程池进行复用。
核心线程池的内部实现
无论是newFixedThreadPool()、newSingleThreadExecutor()还是newCachedThreadPool(),他们的内部都是通过ThreadPoolExecutor类来实现的。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize:线程池中线程数量。
- maximumPoolSize:线程池中最大线程数量
- keepAliveTime:超过corePoolSize的多余线程,在多久时间内会被销毁。
- unit:keepAliveTime的时间单位。
- workQueue:任务队列,被提交但是未被执行的任务。
- threadFactory:线程工厂,用于创建线程。
- handler:拒绝策略。当任务太多来不及处理时,如何拒绝策略。
自定义一个线程池
public class ThreadPoolConfig {
/**
* 核心线程数
*/
private static final int corePoolSize = 4;
/**
* 最大线程数
*/
private static final int maxPoolSize = 8;
/**
* 多余线程最大空闲时间
*/
private static final int keepAlive = 30;
/**
* 线程池缓冲队列
* 如果不手动指定容量,默认为Integer.MAX_VALUE,也就是无界队列。
*/
private static final BlockingQueue poolQueue = new LinkedBlockingQueue(64);
private static volatile ThreadPoolExecutor poolExecutor;
private ThreadPoolConfig(){}
public static ThreadPoolExecutor getInstance(){
if (poolExecutor == null){
synchronized (ThreadPoolConfig.class){
if (poolExecutor == null){
poolExecutor = new ThreadPoolExecutor(corePoolSize,
maxPoolSize,
keepAlive,
TimeUnit.SECONDS,
poolQueue,
new ThreadPoolExecutor.DiscardOldestPolicy());
}
}
}
return poolExecutor;
}
}
再提供一个util用于向线程池中提交任务
public class ThreadPoolUtil {
private static ThreadPoolExecutor poolExecutor = ThreadPoolConfig.getInstance();
public static String submit(Callable callable) throws ExecutionException, InterruptedException {
Future<String> future = poolExecutor.submit(callable);
String result = future.get();
return result;
}
public static void execute(Runnable runnable){
poolExecutor.execute(runnable);
}
public static void shutdown(){
poolExecutor.shutdown();
}
}
以上两部分代码即完成了线程池的定义,下面写一些代码测试一下
public class TestThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
String re = ThreadPoolUtil.submit(() -> {
System.out.println("do something...");
return "success";
});
System.out.println(re);
ThreadPoolUtil.execute(() -> System.out.println("I'm a little thread."));
ThreadPoolUtil.shutdown();
}
}