- 学习笔记 《 深刻了解 Java 虚拟机》
- 学习笔记 《 后端架构设计》
- 学习笔记 《 Java 基础知识进阶》
- 学习笔记 《 Nginx 学习笔记》
- 学习笔记 《 前端开发杂记》
- 学习笔记 《 设计模式学习笔记》
- 学习笔记 《 DevOps 最佳实际指南》
- 学习笔记 《 Netty 入门与实战》
- 学习笔记 《 高性能MYSQL》
- 学习笔记 《 JavaEE 罕用框架》
- 学习笔记 《 Java 并发编程学习笔记》
- 学习笔记 《 分布式系统》
- 学习笔记 《 数据结构与算法》
1、线程状态阐明
Java 的线程在运行阶段会有不同的状态,在Java代码中体现为一个枚举类 Thread.State
其定义如下:
public enum State { // 尚未启动的线程状态,个别是创立好的线程尚未调用start() 办法局处于NEW状态 NEW, // 线程处于可运行的状态,示意能够被JVM执行,然而也可能处于期待其余资源的状态,例如期待处理器的资源 // JVM 概述的将可运行与运行中,统称为RUNABLE RUNNABLE, // 线程处于阻塞状态,示意线程正在期待获取锁,个别是synchronized代码或者调用某个对象wait()办法 // 临时获取不到锁,处于其余资源开释锁的期待状态 BLOCKED, /** * 线程状态处于期待状态,可能是调用以下的办法: * <li>{@link Object#wait() Object.wait}</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * * 或者是处于期待状态的线程在期待其余线程执行特定的动作,比方以后线程调用了某个对象的Object.wait()办法 * 该线程将会期待其余线程调用该对象的Object.notify()办法或者Object.notifyAll()办法 * 或者调用了Thread.join()办法的线程期待其余线程的实现,即期待其余线程进入TERMINATED状态 */ WAITING, /** * 线程处于无限工夫的期待,个别是调用的了蕴含工夫的期待放办法,比方上面的办法 {@link #sleep Thread.sleep} 休眠了肯定的工夫 {@link Object#wait(long) Object.wait} {@link #join(long) Thread.join} with timeout {@link LockSupport#parkNanos LockSupport.parkNanos} {@link LockSupport#parkUntil LockSupport.parkUntil} */ TIMED_WAITING, /** * 线程处于沦亡状态,示意线程曾经执行实现。 */ TERMINATED;
2、线程状态的切换流程
通过上文的枚举状态阐明,咱们理解到Java程序运行的代码状态的具体含意,线程在本身切换的生命周期中,并不是固定处于某个状态,而是随着代码的执行在不停地切换,下图概述了Java线程的状态切换流程。
- 创立新的线程,在调用start()办法之前状态为
NEW
- 调用start()办法,线程由
NEW
进入RUNNABLE
状态,JVM抽象的将正在运行和期待CPU执行统称为RUNNABLE
- 如果调用 Object.wait() 或者LockSupport.park() 办法则进入WAITING状态,当其余线程调用Object.notify()或者Obeject.notifyAll() 办法时候,线程可能会复原为
RUNABLE
, 如果设置期待超时参数,则会进入TIMED_WAITING
状态
比方多个线程都在期待某个对象的notify()办法或者notifyAll()被调用,在复原的时候可能就是随机抉择一个期待该对象nofify()的线程复原,其余线程持续期待,所以此处才申明有可能复原为RUNABLE状态
- 调用 Thread.join() 办法也会进入WAITING或者TIMED_WAITING状态,只有在对应的线程沦亡后,才会跳出 WAITING 或者TIMED_WAITING 状态
- 当程序进入同步办法或者同步代码块的时候,即进入
synchronized
关键字润饰的办法或者代码块的时候,则进入阻塞状态
个别其余的Lock同步的话,则会进入WAITING或则TIMED_WAITING 状态,而非 BLOCKED 状态
- 程序执行实现后进入
TERINATED
状态
3、守护线程
顾名思义,守护线程就是守护其余线程的执行,当过程没有非守护过程的时候,JVM就会退出 (只有过程中存在非守护线程,VM才不会退出)。它次要用于在程序后盾进行调度以及其余反对。能够通过 Thread.setDaemon(bool)
来设置以后线程是是守护线程(传参true)还是用户线程(传参false)。该设置仅在Thread处于NEW状态时候设置无效,不能在线程启动之后设置。如果设置则会抛出异样 IllegalThreadStateException
。
public final void setDaemon(boolean on) { checkAccess(); if (isAlive()) { throw new IllegalThreadStateException(); } daemon = on;}/** * Tests if this thread is alive. A thread is alive if it has * been started and has not yet died. */public final native boolean isAlive();
当JVM退出的时候,守护线程并不一定会执行结束,比方并不会执行finally办法,所以咱们并不能依赖守护线程的finally办法来进行资源的敞开或者开释。比方上面的代码
public class DaemonThread implements Runnable { @Override public void run() { try { SleepUtils.sleep(2); } finally { // 此代码并不会被执行 System.out.println("DaemonThread.run.finally"); } } public static void main(String[] args) { Thread thread = new Thread(new DaemonThread(), "DaemonThread"); thread.setDaemon(true); thread.start(); }}
在上一篇文章线程的创立,展现了一段线程创立的init() 办法的代码,外面的代码展现了线程的是否是守护线程会被继承到其创立的线程的,也就是说守护线程创立的线程,默认也是守护线程
this.daemon = parent.isDaemon();