1.线程池的核心参数
corePoolSize - 核心线程数
maximumPoolSize - 最大线程数
keepAliveTime - 生存时间
unit - 时间单位
workQueue - 阻塞线程队列
threadFactory - 线程工厂
handler - 拒绝策略
源码里某些类和接口的一些关系:
ThreadPoolExecutor —继承—> AbstractExecutorService —实现—>ExecutorService(接口) —继承—> Executor(函数式接口)
Executors 类 (注意和上面的Executor接口不一样) 提供了使用了 ThreadPoolExecutor 的简单的 ExecutorService 实现,比如可以通过Executors.newFixedThreadPool()来创建线程池,底层还是调用new ThreadPoolExecutor来创建线程池
一个简单demo:
public class Main {
static public class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s){
this.command=s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" Start. Command = "+command);
processCommand();
System.out.println(Thread.currentThread().getName()+" End.");
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString(){
return this.command;
}
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("" + i);
executor.execute(worker);
}
executor.shutdown(); // This will make the executor accept no new threads and finish all existing threads in the queue
while (!executor.isTerminated()) { // Wait until all threads are finish,and also you can use "executor.awaitTermination();" to wait
}
System.out.println("Finished all threads");
}
}
自定义拒绝策略,实现RejectedExecutionHandler接口,并监控线程池:
/**
* 自定义线程实现Runnable
*/
class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s){
this.command=s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" Start. Command = "+command);
processCommand();
System.out.println(Thread.currentThread().getName()+" End.");
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString(){
return this.command;
}
}
/**
* 自定义拒绝策略
*/
class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println(r.toString() + " is rejected");
}
}
/**
* 监控线程池信息的线程
*/
class MyMonitorThread implements Runnable
{
private ThreadPoolExecutor executor;
private int seconds;
private boolean run=true;
public MyMonitorThread(ThreadPoolExecutor executor, int delay)
{
this.executor = executor;
this.seconds=delay;
}
public void shutdown(){
this.run=false;
}
@Override
public void run()
{
while(run){
System.out.println(
String.format("[monitor] [%d/%d] Active: %d, Completed: %d, Task: %d, isShutdown: %s, isTerminated: %s",
this.executor.getPoolSize(),
this.executor.getCorePoolSize(),
this.executor.getActiveCount(),
this.executor.getCompletedTaskCount(),
this.executor.getTaskCount(),
this.executor.isShutdown(),
this.executor.isTerminated()));
try {
Thread.sleep(seconds*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
//RejectedExecutionHandler implementation
RejectedExecutionHandlerImpl rejectionHandler = new RejectedExecutionHandlerImpl();
//Get the ThreadFactory implementation to use
ThreadFactory threadFactory = Executors.defaultThreadFactory();
//creating the ThreadPoolExecutor
ThreadPoolExecutor executorPool = new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), threadFactory, rejectionHandler);
//start the monitoring thread
MyMonitorThread monitor = new MyMonitorThread(executorPool, 3);
Thread monitorThread = new Thread(monitor);
monitorThread.start();
//submit work to the thread pool
for(int i=0; i<10; i++){
executorPool.execute(new WorkerThread("cmd"+i));
}
Thread.sleep(30000);
//shut down the pool
executorPool.shutdown();
//shut down the monitor thread
Thread.sleep(5000);
monitor.shutdown();
}
}
2. 线程池的执行原理
提交任务后,最多3步
- 核心线程是否全都被占用。如果没有全被占用,就分配一个核心线程执行任务
- 阻塞队列是否已满。如果没满,就放入阻塞队列
- 线程数是否小于最大线程数。如果是,就创建非核心线程去执行任务
如果上面都不行,就执行拒绝策略。默认的拒绝策略是直接抛出异常。
为什么不允许用Executors去创建线程池?推荐方式是什么?
比如说newFixedThreadPool:他的阻塞队列没有指定容量,可能会造成请求处理队列里有很多堆积,耗费很大的内存,甚至OOM
再比如说newCachedThreadPool():他new的ThreadPoolExecutor的最大线线程数是Integer.MAX_VALUE,有可能会创建非常多的线程,甚至OOM
推荐方式:
自定义Spring线程工厂bean,使用时直接注入bean对象调用execute方法即可。