搜索
写经验 领红包
 > 影视

线程怎么启动怎么停止(线程启动的两种方式)

导语:面试官:线程如何启动和优雅的终止

本节讲解的内容是线程的初始化、线程启动、线程中断、suspend()、resume()、stop()和优雅的关闭线程。
1.线程初始化和线程的启动

首先看下Thread的构造方法:

    public Thread(Runnable target, String name) {        init(null, target, name, 0);    }

当然Thread有多个构造方法,都是调用init方法初始化一个线程。看下init的定义:

 private void init(ThreadGroup g, Runnable target, String name,                      long stackSize, AccessControlContext acc,                      boolean inheritThreadLocals) {                      ...                      }

包含了所属线程组、Runable对象、线程名称、线程的栈大小、访问控制权和inheritThreadLocals。当我们通过new关键字创建线程的时候,默认由当前线程来进行空间分配的,而创建出来的线程继承了当前线程的是否为守护线程、线程优先级、contextClassLoader以及ThreadLocal。创建好的线程对象初始化完成后,在堆内存中等待执行。

注意,创建线程时最好执行线程的名字,方便通过命令jstack分析堆栈信息和问题排查。如果不手动指定线程名称,默认是Thread-&34;work-thread&34;sleeper-thread&34;work-thread interrupt is &34;sleeper-thread interrupt is &34;NEW&39;t change to // not-NEW because we hold the lock. if (threadStatus != 0) { resume(); // Wake up thread if it was suspended; no-op otherwise } // The VM can handle all thread states stop0(new ThreadDeath()); }

最终通过调用stop0(new ThreadDeath())函数,stop0是Native函数,参数是ThreadDeath,ThreadDeath是一个异常对象,该对象从Native层抛到了Java层。线程运行中遇到异常,会导致线程停止,不过不会引起程序退出。

线程是因为异常而停止的,锁会释放,但是不会释放其他的资源,比如打开的socket连接或者IO,多不会关闭,引发内存泄漏。

很多时候为了保证数据安全,线程中会编写同步代码,如果当线程正在执行同步代码时,此时调用stop,引起抛出异常,导致线程持有的锁会全部释放,此时就不能确保数据的安全性,出现无法预期的错乱数据,还有可能导致存在需要被释放的资源得不到释放,引发内存泄露。所以用stop停止线程是不推荐的。

4.优雅的终止线程

关闭线程,肯定等到线程释放掉资源,以免造成内存泄漏,所以不建议使用stop方法。那么应该怎么关闭线程呢?答案是两阶段终止模式。

两阶段终止模式,顾名思义,分两个阶段。第一个阶段,向线程发送终止指令,记住这里只是设置一个终止标识位。第二阶段,线程响应指令,然后终止。这里就用到了,Thread.interrupt()方法来设置终止标识位。我们先看一张图如下:

想终止线程,也就是线程是终止状态,如上图所示,线程只能是RUNNABLE状态才可以到终止状态。所以线程目前状态可以能是RUNNABLE状态,或者是休眠状态。当线程是休眠状态,当我们设置中断标识位时,线程立马会抛出InterruptedException,并且JVM会清除中断标识位,所以在捕获InterruptedException异常后,需要重新设置中断标识位。如下代码:

public class StopThread {    public static void main(String[] args) throws InterruptedException {        Thread t = new Thread(() -> {            System.out.println(&34;);            while(!Thread.currentThread().isInterrupted()) {                System.out.println(&34;);                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                    Thread.currentThread().interrupt();                }            }            System.out.println(&34;);        }, &34;);        t.start();        Thread.sleep(10000);        t.interrupt();    }}

线程t每次执行while内代码,休眠1000ms,然后继续执行,主线程在休眠10000ms后,线程t设置中断标识位,此时,如果线程t还在sleep中,则抛出InterruptedException异常,JVM清除中断标识位,重新设置中断标识位后,下次执行while代码,条件不符合,线程执行完毕。这样,就完成了两阶段模式。

总结:

线程启动使用start方法,而线程run方法,不会启动一个线程。Thread.interrupt(),设置中断标识位,具体是否结束线程,线程自己控制。suspend()、resume()、stop(),这三个方法已经不建议使用,有可能造成死锁和内存泄漏。通过两阶段提交模式,来优雅的终止线程。

本文内容由小森整理编辑!