学习总结-线程的启动与停止

目录

线程的状态

线程的创建

继承 Thread 类创建线程 

实现 Runnable 接口创建线程

实现 Callable 接口通过 FutureTask 包装器来创建Thread 线程

线程的停止 

interrupt() 

Thread.interrupted()

isInterrupted()

其他的线程复位方式

为什么要复位

其他的线程终止方式


  • 线程的状态

线程一共有 6 种状态(NEW、RUNNABLE、BLOCKED、WAITING、TIME_WAITING、TERMINATED)

NEW:初始状态,线程被构建,但是还没有调用 start 方法。、

RUNNABLED:运行状态,JAVA 线程把操作系统中的就绪和运行两种状态统一称为“运行中”。

BLOCKED:阻塞状态,表示线程进入等待状态,也就是线程因为某种原因放弃了 CPU 使用权,阻塞也分为几种情况。

等待阻塞:运行的线程执行 wait 方法,jvm 会把当前线程放入到等待队列。

同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被其他线程锁占用了,那么 jvm 会把当前的线程放入到锁池中。

其他阻塞:运行的线程执行 Thread.sleep 或者 t.join 方法,或者发出了 I/O请求时,JVM 会把当前线程设置为阻塞状态,当 sleep 结束、join 线程终止、io 处理完毕则线程恢复。

TIME_WAITING:超时等待状态,超时以后自动返回。

TERMINATED:终止状态,表示当前线程执行完毕。

 

  • 线程的创建

  • 继承 Thread 类创建线程 

Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过 Thread 类的 start()实例方法。start()方法是一个native 方法,它会启动一个新线程,并执行 run()方法。

  • 实现 Runnable 接口创建线程

如果自己的类已经 extends 另一个类,就无法直接 extends Thread,此时,可以实现一个 Runnable 接口

  • 实现 Callable 接口通过 FutureTask 包装器来创建Thread 线程

有的时候,我们可能需要让一步执行的线程在执行完成以后,提供一个返回值给到当前的主线程,主线程需要依赖这个值进行后续的逻辑处理,那么这个时候,就需要用到带返回值的线程了。

  • 线程的停止 

线程的终止,并不是简单的调用 stop 命令去。虽然 api 仍然可以调用,但是和其他的线程控制方法如 suspend、resume 一样都是过期了的不建议使用,就拿 stop 来说,stop 方法在结束一个线程时并不会保证线程的资源正常释放,因此会导致程序可能出现一些不确定的状态。

要优雅的去中断一个线程,在线程中提供了一个 interrupt 方法。

  • interrupt() 

当其他线程通过调用当前线程的 interrupt 方法,表示向当前线程打个招呼,告诉他可以中断线程的执行了,至于什么时候中断,取决于当前线程自己。

线程通过检查自身是否被中断来进行响应,可以通过Thread.interrupted()或Thread.currentThread().isInterrupted()来判断是否被中断,这个判断过程应该处于一个循环监听中。

  • Thread.interrupted()

Thread类的静态方法,用于测试当前线程是否处于中断状态。若处于中断状态则清除中断状态。

如果连续两次调用该方法,那么第一次调用时,如果当前线程已经处于中断状态,那么该方法会返回true,同时清除当前线程被标记的中断状态。第二次调用时,(第二次调用之前,没有再次调用Thread.currentThread().interrupt();)就会返回false了。

  • isInterrupted()

仅用于判断Thread对象是否已经处于中断状态。不具有清除中断状态功能。

    /**
     * Tests whether the current thread has been interrupted.  The
     * <i>interrupted status</i> of the thread is cleared by this method.  In
     * other words, if this method were to be called twice in succession, the
     * second call would return false (unless the current thread were
     * interrupted again, after the first call had cleared its interrupted
     * status and before the second call had examined it).
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if the current thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see #isInterrupted()
     * @revised 6.0
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

    /**
     * Tests whether this thread has been interrupted.  The <i>interrupted
     * status</i> of the thread is unaffected by this method.
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if this thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see     #interrupted()
     * @revised 6.0
     */
    public boolean isInterrupted() {
        return isInterrupted(false);
    }

    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     */
    private native boolean isInterrupted(boolean ClearInterrupted);
  • 其他的线程复位方式

除了通过 Thread.interrupted 方法对线程中断标识进行复位以外,还有一种被动复位的场景,就是对抛出 InterruptedException 异常的方法,在InterruptedException 抛出之前,JVM 会先把线程的中断标识位清除,然后才会抛出 InterruptedException,这个时候如果调用 isInterrupted 方法,将会返回 false。

  • 为什么要复位

Thread.interrupted()是属于当前线程的,是当前线程对外界中断信号的一个响应,表示自己已经得到了中断信号,但不会立刻中断自己,具体何时中断由自己决定,让外界知道在自身中断前其中断状态仍然是false,这就是复位的原因。

如果是仅仅查看某个线程此刻的中断状态,应该使用isInterrupted()方法。

  • 其他的线程终止方式

定义一个 volatile 修饰的成员变量,来控制线程的终止。这实际上是应用了volatile 能够实现多线程之间共享变量的可见性这一特点来实现的。interrupt ()方法的本质也是如此。

猜你喜欢

转载自blog.csdn.net/u011212394/article/details/82056142