线程的生命周期

1 线程的定义

1.1 线程是什么

线程是操作系统能够运算调度的最小单位。它被包含在进程中,是进程中的实际运行单位,一个进程中包含一个或多个线程,多个线程共享进程中的资源,线程之间的运行互不影响。

1.2 线程和进程的区别

线程与进程的区别可以归纳为以下4点:
1)地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
2)通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
3)调度和切换:线程上下文切换比进程上下文切换要快得多。
4)在多线程OS中,线程不是一个可执行的实体。

2 线程的生命周期

2.1 线程的生命周期有哪些

PS:本文中主要讲述的是基于java中线程的状态

Java中的Thread状态是通过一个名为threadStatus的变量进行存储的。

private volatile int threadStatus = 0;

Thread中有一个枚举,枚举中定义线程所有的状态

public enum State {
        // 初始状态,还没调用start方法
        NEW,

        // 运行状态,调用start方法后的状态
        RUNNABLE,

       // 阻塞状态
        BLOCKED,

        /**
         * 	没有时间的等待,执行下面这些方法后,线程就转换为WAITING状态
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         */
        WAITING,

        /**
         *  有时间的等待,执行下面这些方法后,线程状态就转换为TIME_WAITING状态
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         *  终止状态,当线程的run方法执行完后,就会转换为终止状态
         */
        TERMINATED;
    }

2.2 线程的生命周期是如何转换的

线程的生命周期进行转换的具体情况:
在这里插入图片描述

现在我们来用代码实现线程状态转换:

public class ThreadStatusDemo {

    public static void main(String[] args) {
        // 1. Test Thread Time_Waiting_Thread
        new Thread(() -> {
            while (true){
                try {
                    TimeUnit.SECONDS.sleep(1);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }, "Time_Waiting_Thread").start();

        // 2. Test Thread Waiting_Thread
        new Thread(() -> {
            while (true){
                synchronized (ThreadStatusDemo.class){
                    try {
                        ThreadStatusDemo.class.wait();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }, "Waiting_Thread").start();


        // 3. Test Thread Blocked
        new Thread(new BlockDemo(), "Blocked01_Thread").start();
        new Thread(new BlockDemo(), "Blocked02_Thread").start();
    }

    static class BlockDemo extends Thread{
        @Override
        public void run() {
            synchronized (BlockDemo.class){
                while (true){
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

将程序程序后,程序会处于阻塞状态。通过以下步骤来查看各个线程的状态

  • 运行ThreadStatusDemo程序
  • cmd中执行JPS命令后,查看名为ThreadStatusDemo的进程,记录进程号
  • cmd中执行 jstack 进程号,可以看到每个线程目前的状态 ,如图所示
    在这里插入图片描述
    名为Time_Waiting_Thread的线程执行sleep方法后,线程状态是TIME_WAITING;
    名为Waiting_Thread的线程执行没有时间参数wait方法后,线程状态是WAITING;
    名为Blocked01_Thread的线程成功获取到锁后,调用sleep方法,线程状态是TIME_WAITING;
    名为Blocked02_Thread的线程没有获取到锁,线程状态是BLOCKED;

3 经典问题

3.1 线程的启动为什么是start方法

run方法中一般是我们线程具体要执行的业务代码,使用线程的目的就是通过创建新的线程异步执行run方法,并发执行,从而提高程序运行效率。如果直接调用run方法,相当于调用一个普通的方法,没有创建新的线程。我们来分析下Thread中start方法具体做了些什么:

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

start方法中调用start0方法,而start0方法是native方法,无法看到具体实现的。可以通过查看hotspot源码查看具体流程。

首先,我们需要下载hotspot源码;Hotspot源码地址
其次,定位start0方法在hotspot中具体的位置。
在这里插入图片描述
从上图中可以看到start0方法对应的位置,在jvm.cpp文件找到JVM_StartThread方法。

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))

该方法中有一些关键的实现

3.1.1 创建java线程

在这里插入图片描述
JavaThread构造中是通过操作系统来创建线程的
在这里插入图片描述

3.1.2 启动该java线程

启动java线程
同样的也是通过操作系统来进行线程的启动的
在这里插入图片描述
首先创建一个java线程,然后调用start方法启动该java线程。

3.2 线程的优雅终止

3.2.1 stop方法终止线程

Thread中定义了一个stop方法,调用该方法后,可以直接终止线程。但是在jdk中是不推荐使用的,这种方式相当于在linux中执行kill -9命令,直接停止线程,对程序极不友好。就像当你在吃饭的时候,别人突然打断你一样。
在这里插入图片描述

3.2.2 如何优雅的终止线程

3.2.2.1 方式一

下面展示一个Demo如何优雅的终止线程:

public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (Thread.currentThread().isInterrupted()) {   // 默认的中断标志是false
                i++;
            }
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();     // 将线程的中断标志设置为true
    }

每个线程都有一个boolean类型中断标志,默认该中断标志是false。当调用线程的interrupt方法后,该中断标志会被修改为true。从上面的Demo中我们可以实现线程的优雅关闭,这种方式是利用线程本身自带的中断标志进行终止线程的。

3.2.2.2 方式二

同上,也可以自定义一个变量,在某个时刻修改该变量的值,让线程终止,道理和方式一是一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值