1. 写在前面
我们或许都知道Thread类可以创建线程,也基本都学习过代理模式的相关知识,但Thread和代理模式有什么关系?或许有相当一部分人不太清楚。其实,Thread是用到了静态代理模式的。那是为什么呢?来,看完这篇文章你就知道了。
2. 先回顾下静态代理
我们都知道,静态代理,可以增强被代理对象的功能,完成被代理对象所做不了的事儿,而被代理对象只需要专心做它自己需要做的事情就好了。其他的交给代理对象来完成。哈哈,是不是被说迷糊了,ok,我们来看个例子,相信看完你就清楚静态代理是做了什么事儿了。
假如你要结婚,那一般都要找一家第三方机构比如婚庆公司来委托办理。在结婚之前帮你选场地布置场地等,在结婚之后帮你收拾场地。而你,就可以更加专心的打扮自己,只需要在结婚时闪亮登场。其他的事儿婚庆公司都帮你做了。在这里,婚庆公司就是一个代理,你就是被代理对象。这是之前学习的时候看过的例子,很形象。那么怎么用代码去实现呢?
public class ThreadDemo {
public static void main(String[] args) {
Man man = new Man();
WeddingCompany weddingCompany = new WeddingCompany(man);
weddingCompany.doMarry();
}
}
// 新郎和婚庆公司都要实现的接口
interface Marry {
public void doMarry();
}
// 新郎类
class Man implements Marry{
@Override
public void doMarry() {
System.out.println("我是新郎,正在结婚");
}
}
// 婚庆公司类
class WeddingCompany implements Marry {
Marry target; // 存放被代理对象
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void doMarry() {
System.out.println("我是婚庆公司,在结婚之前,我在布置场地。。。");
target.doMarry();
System.out.println("我是婚庆公司,在结婚之后,我在收拾场地。。。");
}
}
输出结果:
解释一下:在这里我首先声明了一个接口Marry,然后分别创建实现了此接口的新郎类Man和婚庆公司类WeddingCompany。在婚庆公司类里面的接口实现方法doMarry中,调用了新郎类的接口实现方法doMarry,并且在它之前和之后都做了一些事情。最终,只需要委托婚庆公司,即可完成结婚的全部流程。
再抽象一点,就是被代理类和代理类都要实现同一个接口,并且代理类的接口实现方法里面,要调用被代理类的接口实现方法。这样,只需调用代理类的接口实现方法,即可完成需求。
这,就是静态代理。
3. 静态代理,和Thread啥关系
我们先把上面的代码,和线程创建调用的代码,放到一起对比一下
WeddingCompany weddingCompany = new WeddingCompany(new Man()); // 创建代理对象
weddingCompany.doMarry(); // 开始结婚
Thread thread = new Thread(new ThreadSun()); // 创建线程对象
thread.start(); // 开始线程
-------------------------------------------------------------------------------------------
// ThreadSun是一个实现了Runnable接口的类
class ThreadSun implements Runnable {
@Override
public void run() {
System.out.println("我是线程ThreadSon");
}
}
-------------------------------------------------------------------------------------------
你会发现,这里调用格式就好像啊。接下来,我们只需要把静态代理的特点和Thread进行对比,就可以验证Thread是不是用到静态代理了。
首先,Thread作为代理类,它和被代理类,比如这里的ThreadSun,有没有实现同一个接口?答案:有,是Runnable接口。
ThreadSun实现了Runnable很明显,Thread呢?我们可以看下源码,
发现它其实也是实现了
Runnable接口的
然后,代理类Thread和被代理类ThreadSun,有没有实现同一个方法,且在Thread的接口实现方法里面,有没有对ThreadSun的接口实现方法完成调用?答案:有,看run方法。
Runnable接口要求实现run方法,在ThreadSun里面显然已经实现了run方法,Thread方法呢?还是看源码
发现它也实现了
run方法,并调用了target的run方法。我们先不急继续验证,按照静态代理的思想,结合上面婚庆公司的例子,这里的target应该是Runnable的接口对象。来,验证一下:
果然!!!验证完毕。
4. 结论
当我们使用实现Runnable接口来创建线程的时候,其实用到了静态代理。Thread是代理类,实现Runnable接口的类是被代理类。两者都实现了Runnable接口,都实现了run方法,并且在Thread的run方法里面,有调用被代理类的run方法。