这篇文章主要是结合ThreadPoolExecutor实现线程复用的方式,来说明一下静态代理的使用
首先我们先举一个静态代理的例子,这里我们直接用Runable举例。
public static void main(String[] args) {
Runnable runnableA = ()-> System.out.println(Thread.currentThread().getName()+"-业务A");
new Thread(runnableA).start();
Runnable runnableB = ()-> System.out.println(Thread.currentThread().getName()+"-业务B");
new Thread(runnableB).start();
}
假如我们有这样一个简单的需求,我需要输出线程执行前后的时间。我们会怎么做?
public static void main(String[] args) {
Runnable runnableA = ()-> {
long startTIme = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+"-业务A");
long endTime = System.currentTimeMillis();
System.out.println("执行时间:"+(endTime-startTIme));
};
new Thread(runnableA).start();
Runnable runnableB = ()-> System.out.println(Thread.currentThread().getName());
new Thread(runnableB).start();
}
是不是会想到上面的例子,有些爱整洁的同学可能会把时间这段封装一下,让A,B两个线程都适用。但是这里是不是有个问题。我们修改了runnableA的内部实现!我们以后使用runnableA的时候,它是不是不止会打印线程,还会输出执行时间!那原本只执行业务的方法就没有了。
使用静态代理
说说我们为什么要使用静态代理,当我们需要对某些功能进行通用的增强时,为了不修改原有的功能,我们就能使用静态代理对功能进行增强。其实也是就开闭原则。
public class StaticProxyTest {
public static void main(String[] args) {
Runnable runnableA = ()-> System.out.println(Thread.currentThread().getName()+"-业务A");
Runnable proxyA = new ProxyRunnable(runnableA);
new Thread(proxyA).start();
Runnable runnableB = ()-> System.out.println(Thread.currentThread().getName()+"-业务B");
Runnable proxyB = new ProxyRunnable(runnableB);
new Thread(proxyB).start();
}
public static class ProxyRunnable implements Runnable{
private final Runnable runnable;
public ProxyRunnable(Runnable runnable) {
this.runnable = runnable;
}
@Override
public void run() {
long startTIme = System.currentTimeMillis();
runnable.run();
long endTime = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+"-执行时间:"+(endTime-startTIme));
}
}
}
上面的代码可以看到,我们的业务代码,没有改变;我们通过代理对象,返回的类型,也通过原有的接口进行了接收,只需要在使用的时候,通过代理对象使用就行。
ThreadPoolExecutor对静态代理的使用
ThreadPoolExecutor在进行线程复用的时候,使用到了静态代理,我们看下它的具体实现。
首先,我们看入口execute()方法
// 传入的是一个Runnable
public void execute(Runnable command){
//......
//在内部会被包装成一个worker
addWorker(command, true);
//......
}
// core为true 代表使用核心线程
private boolean addWorker(Runnable firstTask, boolean core){
//......
// 把你传入的线程,传入Worker
new Worker(firstTask);
//......
try {
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 c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
workers.add(w);
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 调用work中的Thread.start启动线程
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
}
// 可以看到,Worker也实现了Runnable,并且在run()方法中调用了其他Runnable的run()方法
// 这里就可以理解为Worker是Runnable的一个代理对象
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
//......
//执行的线程
final Thread thread;
/** Initial task to run. Possibly null. */
// 你传入的Runable
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
// TODO: switch to AbstractQueuedLongSynchronizer and move
// completedTasks into the lock word.
/**
* 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 = getThreadFactory().newThread(this);
}
// 重写run方法
public void run() {
// 对你传入的runable增强
runWorker(this);
}
//......
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 这里就是线程复用的逻辑
// runWorker是woker的run方法调用的
// 这里while就是为什么能够复用
// runWorker先是调用用户传入的Runnable,执行完后回来while,重新通过getTask()获取一个新的runnable,然后执行
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);
try {
task.run();
afterExecute(task, null);
} catch (Throwable ex) {
afterExecute(task, ex);
throw ex;
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
总结
下面写一段伪代码来总结一下ThreadPoolExecutor是怎么通过静态代理实现线程复用的
//核心的复用代码其实在Worker内部
public class Worker implements Runnable {
@Getter
Thread thread;
Runnable task;
public Worker(Runnable task) {
this.thread = new Thread(this, "线程B");
this.task = task;
}
@Override
public void run() {
// 这里是通过线程的start方法启动的
// 在这个run里面循环调用其他runnable的run方法,实现线程复用
while (task != null ||(task=getTask())!=null) {
task.run();
}
}
public Runnable getTask(){
return ()-> System.out.println("getTask");
}
}
public void execute(Runnable task){
// 我们的业务逻辑
Runnable runnable = ()-> System.out.println("业务逻辑");
// 我们的静态代理对象,和我们业务逻辑都是基于runnable的实现
Worker worker = new Worker(runnable);
// 执行代理方法
worker.getThread().start();
}