Java线程学习第三篇

93 阅读2分钟

「这是我参与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*
########