线程的启动流程剖析及使用的设计模式

14次阅读

共计 2850 个字符,预计需要花费 8 分钟才能阅读完成。

我们都知道,Java 中构造线程的方式有两种,第一种是继承 Thread 类,然后覆写 run 方法;第二种是实现 Runnable 接口,然后实现 run 方法。但是最终启动的时候都是通过 Thread 对象的 start 方法启动的。那么既然逻辑写在了 run 方法中,启动的时候为什么调用 start 方法呢?

1.JDK 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) {}}
}

通过查看源码可以看到,在 start 方法中调用了 start0 这个方法,这个方法的实现如下:

private native void start0();

该方法是 native 方法,表示由 JDK 通过 JNI 来调用的。但是 run 方法何时调用的呢?
通过查看官方文档,可以看到说明,start0 的底层实现中是调用了 run 方法的,只不过是通过 C ++ 实现的,感兴趣的可以翻一下对应的代码。

通过上述 start 方法的源码,可以总结出以下几个点:

  • (1) 当线程被构造完成之后,有个状态变量会记录线程的状态,就是上述的 threadStatus,初始值在类中声明的为 0;
  • (2) 调用 start 方法启动线程之后,threadStatus 的值会被改变。如果再次重复调用 start 方法启动同一个线程时,会抛出 IllegalThreadStateException 异常;
  • (3) thread 线程启动之后,会被加入到一个线程组 ThreadGroup 中;
  • (4) 线程如果启动失败了,线程组会对线程做失败处理,将其从线程组中移除;
  • (5) 如果一个线程生命周期结束了,再次调用 start 方法试图启动线程的时候,会提示 IllegalThreadStateException 异常,也就是处于 TERMINATED 状态的线程没办法重新回到 RUNNABLE 或者 RUNNING 状态;

示例验证 1:验证线程是否可以启动多次

Thread thread = new Thread(){
    @Override
    public void run() {
        try {TimeUnit.MILLISECONDS.sleep(5);
        } catch (Exception e) {e.printStackTrace();
        }
    }
};
thread.start();
thread.start();

运行上述代码,会出现以下异常信息:

Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:705)
at com.wb.spring.test.TestThread.main(TestThread.java:40)

示例验证 2:线程生命周期结束,再次调用 start 方法启动

Thread thread = new Thread(){
    @Override
    public void run() {
        try {TimeUnit.MILLISECONDS.sleep(1);
            System.out.println("线程运行完毕!");
        } catch (Exception e) {e.printStackTrace();
        }
    }
};
// 第一次启动
thread.start();
try {TimeUnit.MILLISECONDS.sleep(3);
} catch (Exception e) {e.printStackTrace();
}
// 第二次启动
thread.start();

运行以上示例代码,将会得到如下的结果:

 线程运行完毕!Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:705)
at com.wb.spring.test.TestThread.main(TestThread.java:48)

从结果中可以看出,线程运行完成之后,生命周期就结束了,不能再次启动。

从上述示例中可以看到,都跑出了 IllegalThreadStateException 异常,但是两次出现该异常的情况却不一样。第一种线程还活着,生命周期未结束,只是不允许多次重复启动;而第二次是因为线程的生命周期已经结束,试图启动已经结束的线程,就会抛出该异常。

2.Thread 类中的设计模式 - 模板设计模式

简介:模板设计模式指的是在继承结构中,父类中来确定算法结构,而具体的算法实现细节交给子类来完成。比如 Thread 类中 run 方法的源码如下,如果使用了 Thread 类的方式构造线程,其实 run 方法相当于一个空的实现,但是调用 start 方法的时候,却能够正确执行子类 run 方法的实现细节。

@Override
public void run() {if (target != null) {target.run();
    }
}

这种设计模式有利于父类确定程序的结构。
模板设计模式示例:

public class TemplateTest {public final void say(String msg) {System.out.println("000000");
        sayHello(msg);
        System.out.println("000000");
    }

    protected void sayHello(String msg) { }

    public static void main(String[] args) {TemplateTest test1 = new TemplateTest() {
            @Override
            protected void sayHello(String msg) {System.out.println("***" + msg + "***");
            }
        };
        test1.say("wb");
        TemplateTest test2 = new TemplateTest() {
            @Override
            protected void sayHello(String msg) {System.out.println("&&&" + msg + "&&&");
            }
        };
        test2.say("bw");
    }
}

输入结果如下:

000000
***wb***
000000
000000
&&&bw&&&
000000

可以看到,需要输入什么符号,可以自由地由子类来控制!这就是模板设计模式带来的好处!

以上就是 Thread 类启动线程的过程及使用的设计模式详解。欢迎评论转发。
另提供一些免费的 IT 视频资料,架构师,高可用,高并发等教程!如需要请查看 https://www.592xuexi.com

正文完
 0