作为一个稀有的Java妹子,所写的所有博客都只是当作自己的笔记,留下证据自己之前是有用心学习的~哈哈哈哈(如果有不对的地方,也请大家指出,不要悄悄咪咪的不告诉我)
为什么需要线程池
首先举例一个业务场景,也是日常开发中经常会遇到的场景,手机短信验证业务。
短信验证在很多业务场景中都会遇到,比如验证码登录,短信提示余额不足等等。类似这种不影响主线程业务的,在访问量很大的情况下,就需要考虑使用多线程开发,避免访问量大时,造成接口阻塞。
那么有人会问了,既然需要多线程开发,那么在代码里直接创建线程来处理就好了呀。这种显示的在代码里创建线程的方式是不可取的,因为如果频繁的创建销毁线程,或者线程数太多,内存切换线程耗时久会造成服务器卡死。
所以,在不阻塞主线程的情况,使用另外的线程来处理某些业务时,就需要使用多线程,又因为频繁创建销毁线程十分耗时,线程池就应运而生啦。
线程池是什么
从字面上理解,就是装有线程的池子,这些线程可以处理特殊的业务,池子里有存放任务的队列,当队列里有任务时,线程会去队列里取任务执行,当队列为空时,线程就会等待。
结合业务场景分析,当需要发送短信时,就调用线程池,线程池会把发送短信的任务放到队列中(不准确,后面会细说,不是直接放队列),线程就会去队列中拿任务,执行发送短信,那么主线程就只管把发送短信的任务往线程池的队列中放,然后继续执行其他的逻辑。
贴一段生产环境的部分业务代码,支付订单成功后,在回调里处理跨境商品报关,当有很多用户支付成功时,这个方法就会被频繁调用,跨境商品报关就可以使用线程池来处理,这样接口的响应就会很快,因为不用等待短信处理的结果。
/**
* 完成支付 回调
*/
public boolean compeletPay(PayOrderRes res) {
// 销售单和收款单 推送金蝶
k3OrderSellSender.send(order.getTransactionNo());
//添加报关记录
transCustomsService.addTransCustomsRecord(order.getTransactionNo());
//跨境商品报关
customsDeclareLogic
.synchCustomsDeclare(order.getTransactionNo(), String.valueOf(order.getUserId()), 2);
}
源码解析
1.继承关系
ThreadPoolExecutor extends AbstractExecutorService
AbstractExecutorService implements ExecutorService
ExecutorService extends Executor
Executor是线程池的顶级接口,只有一个execute方法
public interface Executor {
void execute(Runnable command);
}
ExecutorService继承了Executor,新增了许多方法
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
<T> Future<T> submit(Callable<T> task);
}
2.成员变量
/**
线程池的状态
*/
//调用execute方法后,线程池就进行运行状态
private static final int RUNNING = -1 << COUNT_BITS;
//调用shutdown方法后,线程就不再接收新的任务,正在执行的任务会执行完毕再真正关闭线程池
private static final int SHUTDOWN = 0 << COUNT_BITS;
//调用shutdownNow方法后,线程不再接收新的任务,并且尝试关闭正在执行的线程
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
//当线程为shutdown/stop,且线程全部销毁后,线程池的状态就是终止
private static final int TERMINATED = 3 << COUNT_BITS;
/**
存放任务的队列
*/
private final BlockingQueue<Runnable> workQueue;
/**
存放线程的集合
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
/**
创建线程的工厂
*/
private volatile ThreadFactory threadFactory;
/**
队列里的任务满了时,拒绝处理的handler
*/
private volatile RejectedExecutionHandler handler;
/**
当前线程池中的线程数
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
/**
线程池核心大小,线程里可以有多少线程
*/
private volatile int corePoolSize;
/**
线程池最大线程数
*/
private volatile int maximumPoolSize;
/**
线程保持活跃的时间,当超过核心线程数,就会创建新的线程,这部分线程当不处理任务时,就会判断是否超过活跃时间,超过即销毁
*/
private volatile long keepAliveTime;
3.构造方法
//一共有四个
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
构造方法初始化:核心线程数,最大线程数,活跃时间,时间单元,队列,线程工厂,拒绝处理handler
4.execute方法
//参数是线程,调用该方法就可以把线程放入线程池中,然后执行业务代码
public void execute(Runnable command) {
//判断传进来的线程是否为空,是的话就抛出异常
if (command == null)
throw new NullPointerException();
//获取当前线程池的线程数量
int c = ctl.get();
//与核心线程数比较
if (workerCountOf(c) < corePoolSize) {
//如果小于核心线程数,则在线程池中创建线程
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果当前线程数大于核心线程数,则把线程放到队列中
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果当前线程数大于核心线程数,队列又满了,那么就拒绝处理
else if (!addWorker(command, false))
reject(command);
}
//当线程池中的线程数<核心线程数时,创建worker,即线程
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
//比较线程池的数量与核心线程数量,判断线程池队列是否为空,线程池的状态是否为RUNNING等等
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//将线程池中的线程数+1
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
//当通过检验后,创建线程
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//使用worker创建线程,Worker是ThreadPoolExecutor的内部类,专门用来创建线程,管理线程的
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
//拿到锁后再次判断线程池的状态
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
//添加线程
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
//启动线程,注意这里的start会运行Worker里的Run方法,后面有介绍
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
//内部类Worker
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
final Thread thread;
Runnable firstTask;
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
//看下这个方法
runWorker(this);
}
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
//这个task就是调用execute时传入的线程,这个线程里的run方法里才是业务逻辑代码
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//判断队列是否为空,不为空则从队列中获取任务
while (task != null || (task = getTask()) != null) {
w.lock();
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);
}
}
//从队列获取任务
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?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//获取任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
5.其他方法
1.shutdown()
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
private void checkShutdownAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
}
}
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
6.Executor和Executors的区别
Executor是线程池的顶级接口,Executors提供了一些创建线程池的方法
public class Executors {
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
......
}
举例
我直接贴生产环境的业务代码出来,look look
public class CustomsDeclareLogic {
@Autowired
EpayService epayService;
@Autowired
AlipayService alipayService;
@Autowired
WxPayService wxPayService;
public class CustomsDeclareThread implements Runnable {
private String transactionNo;
private String userId;
/**
* 1新增报关记录,2修改报关记录
*/
private Integer action;
public CustomsDeclareThread(String transactionNo, String userId, Integer action) {
this.transactionNo = transactionNo;
this.userId = userId;
this.action = action;
}
@Override
public void run() {
try {
//处理业务逻辑
declareOrder(transactionNo,userId,action);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getTransactionNo() {
return transactionNo;
}
public void setTransactionNo(String transactionNo) {
this.transactionNo = transactionNo;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
//创建线程池
private static ExecutorService CUSTOMSDECLARE_THREAD_POOL = new ThreadPoolExecutor(
2, 10, 5 * 60L,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r,
"schedule-pool-overseas-customsDeclare" + threadNumber.getAndIncrement());
}
}
);
public void synchCustomsDeclare(String transactionNo, String userId, Integer action) {
//调用execute时,将业务线程放入
CUSTOMSDECLARE_THREAD_POOL
.execute(new CustomsDeclareThread(transactionNo, userId, action));
}
/**
*
* @param transactionNo 支付单号
* @param userId 用户id
* @param action 1新增报关记录,2修改报关记录
*/
public void declareOrder(String transactionNo,String userId,Integer action){
System.out.println(transactionNo + "+++++" + userId);
List<PTbOrder> orderList = orderService.selectOrderByTransactionNo(transactionNo, userId);
PTbTransaction tbTransaction = transactionService
.selectTransactionByTransactionNo(transactionNo);
for (PTbOrder pTbOrder : orderList) {
String warehouseType = pTbOrder.getWarehouseType();
if ("INBONDED".equals(warehouseType)) {
//报关方式判断
if ("EPAY_WX_APP".equals(tbTransaction.getPayMethod()) || "EPAY_WX_WEB"
.equals(tbTransaction.getPayMethod())) {//网易支付报关
log.info("++++网易支付跨境商品报关++++start" + transactionNo);
epayService.customsDeclare(tbTransaction, pTbOrder, String.valueOf(action), true,
tbTransaction.getPayMethod());
} else if ("ALIPAY_GUOJI".equals(tbTransaction.getPayMethod())) {//国际支付宝报关
log.info("++++支付宝支付跨境商品报关++++start" + transactionNo);
alipayService
.customsDeclare(tbTransaction, pTbOrder, true, tbTransaction.getPayMethod(),
action, false);
} else if ("WXPAY".equals(tbTransaction.getPayMethod()) || "WXPAY_APP".equals(tbTransaction.getPayMethod()) || "WXLITE".equals(tbTransaction.getPayMethod())) {
log.info("+++++原生微信支付报关+++++start");
wxPayService.customsDeclare(tbTransaction, pTbOrder, true, tbTransaction.getPayMethod(),action);
}
}
}
}
}
文章开篇举例跨境报关的,就是调用的这个类的synchCustomsDeclare方法,在该方法中执行线程池的execute