1、介绍
不使用线程池面临的问题
众所周知,java中线程的创建、切换、销毁都是比较消耗计算机资源的,若是线程执行的任务逻辑比较简单,创建、销毁线程消耗的计算机资源可能大于任务本身。特别是频繁的创建大量的线程,大量的线程在上下文切换的同时,系统也可能变得不稳定。
线程池优点
- 减少资源消耗:通过线程复用,避免重复创建、销毁线程造成额外的资源消耗。
- 提高响应速度:任务到达时,已有线程直接执行任务,无需实时创建线程造成的时间消耗。
- 资源上限管理:线程池的大小是预设的,避免系统无上限创建线程造成内存溢出。
2、7大核心参数
列表
参数 | 说明 |
int corePoolSize | 核心线程数 |
int maximumPoolSize | 最大线程数 |
long keepAliveTime | 空闲线程存活时间 |
TimeUnit unit | 空闲线程存活时间的单位 |
BlockingQueue workQueue | 线程池任务队列 可详见 |
ThreadFactory threadFactory | 创建线程的工厂 |
RejectedExecutionHandler handler | 拒绝策略 |
详解
- corePoolSize:线程池中一直存在的线程数量,即使线程为空闲状态也会一直存在,除非将属性(allowCoreThreadTimeOut)设置为true。
- maximumPoolSize:线程池中允许存在的最大线程数量。
- keepAliveTime:当线程数量大于核心线程数量时,多余且空闲的线程在被销毁前等待任务的最大时间。
- unit:keepAliveTime参数的时间单位,如毫秒、秒、分钟、小时等等。
- workQueue:线程池用来暂时存放任务的阻塞队列。
- threadFactory:线程池创建线程时调用的工厂方法,通过此方法可以设置线程的优先级、线程命名规则以及线程类型(用户线程还是守护线程)等。
- handler:当线程池的任务超出线程池队列可以存储的最大值之后,执行的策略。
图解流程
API图示
3、使用案例
public class Demo {
public static void main(String[] args)throws Exception {
/**
* corePoolSize: 3
* maximumPoolSize: 5
* keepAliveTime: 100
* unit: TimeUnit.MILLISECONDS
* workQueue: new ArrayBlockingQueue<Runnable>(1)
*
* 说明:线程池核心线程数量3,最大线程5,非核心线程空闲存活100毫秒,阻塞队列是基于数组的大小为1的队列。
* 线程工厂、拒绝策略使用ThreadPoolExecutor的默认值。
*/
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 5, 100, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
executor.execute(()->{
Thread thread = Thread.currentThread();
System.out.println("线程名称:"+thread.getName());
System.out.println("线程优先级:"+thread.getPriority());
System.out.println("线程池线程数量:"+executor.getPoolSize());
});
}
}
3、几种常见线程池
在上面的演示案例中,直接调用ThreadPoolExecutor类的构造函数创建线程池,在实际编码时,其实并不需要我们手动创建线程池。
JDK根据不同的使用场景,通过调节7大核心参数,Executors类提供了大量静态函数供我们调用创建线程池。
newCachedThreadPool(可缓存的线程池)
//使用方式
ExecutorService threadPool = Executors.newCachedThreadPool();
//源码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newFixedThreadPool(固定大小的线程池)
//使用方式
ExecutorService threadPool = Executors.newFixedThreadPool(5);
//源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadPool(单个线程的线程池)
//使用方式
ExecutorService threadPool = Executors.newSingleThreadExecutor();
//源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
4、线程复用原理
我们知道,一个线程对象是不能被启动多次的,如下演示:
//代码
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程名称:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
myThread.start();
}
}
//运行结果
线程名称:Thread-0
Exception in thread "main" java.lang.IllegalThreadStateException
那要怎么实现线程复用,让一个线程对象运行多个任务(Runnable)呢,演示简易代码:
//代码
public class MyThread extends Thread {
private BlockingQueue<Runnable> tasks = null;
public MyThread(BlockingQueue<Runnable> tasks){
this.tasks = tasks;
}
@Override
public void run() {
for(;;){
try {
Runnable task = tasks.take();
task.run();
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
ArrayBlockingQueue<Runnable> runnables = new ArrayBlockingQueue<>(3);
runnables.offer(()->System.out.println("线程名称:"+Thread.currentThread().getName()));
runnables.offer(()->System.out.println("线程名称:"+Thread.currentThread().getName()));
runnables.offer(()->System.out.println("线程名称:"+Thread.currentThread().getName()));
MyThread myThread = new MyThread(runnables);
myThread.start();
}
}
//运行结果
线程名称:Thread-0
线程名称:Thread-0
线程名称:Thread-0
JDK8线程池实现线程复用关键源码
/**
* 此类是线程池的任务类,内部封装了Thread属性,启动内部的Thread便会运行Worker的run方法。
*/
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;
/** Initial task to run. Possibly null. */
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
//这里创建线程对象,将对象自身传递进去,this.thread一旦启动(调用start),就会运行Worker类的run方法。
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
//this.thread一旦启动(调用start),run方法就会自动运行
public void run() {
//循环从阻塞队列里面取出Runnable对象,然后执行其run方法。
runWorker(this);
}
// Lock methods
//
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
/**
* Worker类中run方法调用的方法,此方法循坏从阻塞队列里面取出Runnable实现类对象,
* 然后执行Runnable对象的run方法,从而实现了线程的复用。
*/
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
5、线程超时销毁原理
JDK8实现非核心线程超时销毁关键源码
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
/**
* 此处getTask方法为从阻塞队列里面取出Runnable对象
* 如果取出的对象为null,则停止while循环,执行processWorkerExit方法,销毁此Worker任务线程
*/
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
//销毁此Worker任务线程
processWorkerExit(w, completedAbruptly);
}
}
/**
* 从阻塞队列里面取出Runnable对象
*/
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
/**
* allowCoreThreadTimeOut若设置为true,则核心线程也会被超时销毁
* wc > corePoolSize(判断当前线程数量是否大于核心线程数,若大于则当前线程需要做超时销毁)
* 若timed==true:当前任务线程需要做超时销毁操作。
*/
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
/**
* 当阻塞队列为空时
* timed==true:workQueue.poll返回null。
* timed==false:workQueue.take阻塞直到队列中有元素为止。
*/
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}