有的时候,我们可能需要让一步执行的线程在执行完成以后,提供一个返回值给到当前的主线程,主线程需要依赖这个值进行后续的逻辑处理,那么这个时候,就需要用到带返回值的线程了
关于线程基础知识的如果有什么问题的可以在网上查找资料学习学习!这里不再阐述
2. 线程的生命周期
Java 线程既然能够创建,那么也势必会被销毁,所以线程是存在生命周期的,那么我们接下来从线程的生命周期开始去了解线程。
2.1 线程的状态 2.1.1 线程六状态认识
线程一共有 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:终止状态,表示当前线程执行完毕
2.1.2 代码实操演示
代码:
public static void main(String[] args) { ////TIME_WAITING 通过 sleep wait(time) 来进入等待超时中 new Thread(() -> { while (true){ //线程执行内容 try { TimeUnit.SECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } },"Time_Waiting").start(); //WAITING, 线程在 ThreadStatus 类锁上通过 wait 进行等待 new Thread(() -> { while (true){ synchronized (ThreadStatus.class){ try { ThreadStatus.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } },"Thread_Waiting").start(); //synchronized 获得锁,则另一个进入阻塞状态 blocked new Thread(() -> { while (true){ synchronized(Object.class){ try { TimeUnit.SECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } },"Object_blocked_1").start(); new Thread(() -> { while (true){ synchronized(Object.class){ try { TimeUnit.SECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } },"Object_blocked_2").start(); }启动一个线程前,最好为这个线程设置线程名称,因为这样在使用 jstack 分析程序或者进行问题排查时,就会给开发人员提供一些提示
2.1.3 线程的状态堆栈
➢ 运行该示例,打开终端或者命令提示符,键入“ jps ”, ( JDK1.5 提供的一个显示当前所有 java 进程 pid 的命令)
➢ 根据上一步骤获得的 pid ,继续输入 jstack pid (jstack是 java 虚拟机自带的一种堆栈跟踪工具。jstack 用于打印出给定的 java 进程 ID 或 core file 或远程调试服务的 Java 堆栈信息)
3. 线程的深入解析 3.1 线程的启动原理
前面我们通过一些案例演示了线程的启动,也就是调用 start() 方法去启动一个线程,当 run 方法中的代码执行完毕以后,线程的生命周期也将终止。调用 start 方法的语义是当前线程告诉 JVM ,启动调用 start 方法的线程。
我们开始学习线程时很大的疑惑就是 启动一个线程是使用 start 方法,而不是直接调用 run 方法,这里我们首先简单看一下 start 方法的定义,在 Thread 类中
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 { //线程调用的核心方法,这是一个本地方法,native 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 */ } } } //线程调用的 native 方法 private native void start0();