「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
前言
前面的文章里,我们明白了start方法启动了一个线程,并且该线程进入了可执行状态。在第一篇的代码中,重写了Thread对run方法,确调用了start方法,那么run方法和start方法有什么关系呢?接下来就继续学习吧~
Thread start方法源码
public synchronized void start(){
if(threadStatus != 0)
throw new IllegalThreadstateException();
group.add(this);
boolean started = false;
try{
start0();
started = true;
}finally{
try{
if(!started){
group.threadStartFailed(this);
}
}catch(Throwable ignore){
}
}
}
其中最核心的部分是start0这个本地方法,也就是JNI方法:
private native void start0();
通过上述代码可以总结出:
- Thread被构造后的NEW状态,事实上threadStatus这个内部属性为0;
- 不能两次启动Thread,否则就会出现IllegalThreadStateException异常;
- 线程启动后将会被加入到一个ThreadGroup中;
- 一个线程生命周期结束,也就是到了TERMINATED状态,再次调用start()方法是不允许的,也就是说TERMINATED状态是没有办法回到RUNNABLE/RUNNING状态。
模板设计模式在Thread中的应用
通过上述分析,我们不难看出,线程的真正的执行逻辑是在run方法中,通常我们会把run方法称为线程的执行单元,这也回答了最开始的问题,重写run方法,用start方法启动线程。Thread中的run方法的代码如下:
@Override
public void run(){
if(target != null){
target.run();
}
}
如果没有使用Runnable接口对其进行改造,则可以认为Thread的run方法本身就是一个空的实现。其实Thread的run和start就是一个比较典型的模板设计模式,父类编写算法结构代码,子类实现逻辑细节。
public class TemplateMethod{
public final void print(String message){
System.out.println("########");
wrapPrint(message);
System.out.println("########");
}
protected void wrapPrint(String message){}
public static void main(String[] args){
TemplateMethod t1 = new TemplateMethod(){
@Override
protected void wrapPrint(String message){
System.out.println("*"+message+"*");
}
};
t1.print("Hello Thread");
TemplateMethod t2 = new TemplateMethod(){
@Override
protected void wrapPrint(String message){
System.out.println("*"+message+"*");
}
};
t2.print("Hello Thread");
}
}
print方法类似于Thread的start方法,而wrapPrint则类似于run方法,这样做的好处就是程序结构由父类控制,并且是final修饰的,不允许被重写,子类只需要实现想要的逻辑任务即可,输出如下:
########
*Hello Thread*
########
########
*Hello Thread*
########