Java多线程并发02——线程的生命周期与常用方法,你都掌握了吗
在上一章,为大家介绍了线程的一些基础知识,线程的创建与终止。本期将为各位带来线程的生命周期与常用方法。关注我的公众号「Java面典」了解更多 Java 相关知识点。
线程生命周期
一个线程不是被创建了马上就开始执行,也不是一直处于执行状态。在线程的整个生命周期中会经历新建(New)、
就绪(Runnable)、运行(Running)、阻塞(Blocked)和销毁(Terminated)5 种状态。

新建
指使用 new 关键字创建一个新的线程对象后,该线程就处于新建状态。此时仅由 JVM 为其分配内存,并初始化其成员变量的值。
就绪
当线程对象调用了 start() 方法之后,该线程处于就绪状态。JVM 会为其创建方法调用栈和程序计数器,等待调度运行。
运行
如果处于就绪状态的线程获得了 CPU 时钟,开始执行 run() 方法的线程执行体,则该线程处于运行状态。
阻塞
阻塞状态是指线程因为某种原因放弃了 CPU 使用权,暂时停止运行。阻塞的情况分三种:
- 等待阻塞(o.wait->等待对列):运行( running )的线程执行 o.wait( )方法,JVM 会把该线程放入等待队列(waitting queue) 中;
- 同步阻塞(lock->锁池):运行( running )的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池( lock pool )中。
- 其他阻塞(sleep/join): 运行( running )的线程执行 Thread.sleep(long ms)或 t.join()方法,或者发出了 I/O 请求时,JVM 会把该线程置为阻塞状态。当 sleep() 状态超时、join() 等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入可运行( runnable )状态。
销毁
如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源。
线程常用方法
从线程的生命周期中,我们已经了解到了线程的一些常用方法。线程的常用方法有 wait,notify,notifyAll,sleep,join,yield等。
wait
- 作用:强迫一个线程等待,线程进入 WATING 状态,只有等待另外线程的通知或被中断才会返回;
- 注意:调用 wait() 方法后,会释放对象的锁。因此,wait 方法一般用在同步方法或同步代码块中。
sleep
- 作用:强迫一个线程睡眠N毫秒,线程进入 TIMED_WATING 状态, 只有等待另外线程的通知或被中断才会返回;
- 注意:与 wait 方法不同的是 sleep 不会释放当前占有的锁。
yield
- 作用:使当前线程让出 CPU 执行时间片,与其他线程一起重新竞争 CPU 时间片;
- 注意:一般情况下,优先级高的线程有更大的可能性成功竞争得到 CPU 时间片,但这又不是绝对的,有的操作系统对线程优先级并不敏感。
interrupt
- 作用:中断一个线程,其本意是给这个线程一个通知信号,会影响这个线程内部的一个中断标识位;
- 注意:
- interrupt 不会改变线程的状态,即不会强制线程进入阻塞、终止等状态;
- 若线程处于 TIMED-WATING 状态,这时调用 interrupt()方法,会抛出 InterruptedException,从而使线程提前结束 TIMED-WATING 状态;
- 许多声明抛出 InterruptedException 的方法(如 Thread.sleep(long mills 方法)),抛出异常前,都会清除中断标识位,所以抛出异常后,调用 isInterrupted()方法将会返回 false;
- 可以调用 thread.interrupt()方法,在线程的 run 方法内部可以根据 thread.isInterrupted()的值来优雅的终止线程。
join
- 作用:使当前线程转为阻塞状态,直到另一个线程结束,当前线程再由阻塞状态变为就绪状态;
- 使用场景:主线程中启动子线程,主线程等待子线程的返回状态。
System.out.println(Thread.currentThread().getName() + "线程运行开始!");
Thread6 thread1 = new Thread6();
thread1.setName("线程 B");
thread1.join();
System.out.println("这时 thread1 执行完毕之后才能执行主线程");
notify
- 作用:Object 类中的 notify() 方法,唤醒在此对象监视器上等待的单个线程;
如果所有线程都在此对象上等待,则会选择唤醒其中一个线程,选择是任意的,并在唤醒该线程前,调用该线程的 wait() 方法,在对象的监视器上等待,直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。类似的方法还有 notifyAll() ,唤醒在此监视器上等待的所有线程。
其他线程方法
- isAlive():判断一个线程是否存活;
- activeCount():程序中活跃的线程数;
- enumerate():枚举程序中的线程;
- currentThread():得到当前线程;
- isDaemon():判断一个线程是否为守护线程;
- setDaemon():设置一个线程为守护线程;
- setName():为线程设置一个名称;
- getPriority():获取当前线程的优先级;
- setPriority():设置当前线程的优先级。
注意:线程优先级高,被CPU调度的概率大,但不代表一定会运行,还有小概率运行优先级低的线程。
什么是守护线程
定义
守护线程——也称“服务线程”,他是后台线程,它有一个特性,即为用户线程提供公共服务,在没有用户线程可服务时会自动离开;
优先级
守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务;
设置
通过 setDaemon(true)来设置线程为“守护线程”;将一个用户线程设置为守护线程的方式是在线程对象创建之前用线程对象的 setDaemon 方法;
特点
在 Daemon 线程中产生的新线程也是 Daemon 的;
example
垃圾回收线程就是一个经典的守护线程,当我们的程序中不再有任何运行的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是 JVM 上仅剩的线程时,垃圾回收线程会自动离开。它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源;
生命周期
守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。当 JVM 中所有的线程都是守护线程的时候,JVM 就可以退出了;如果还有一个或以上的非守护线程则 JVM 不会退出。
sleep() 与 wait() 的区别
- 所属类不同:sleep() 方法属于 Thread 类,wait() 方法属于 Object 类;
- 锁状态不同:sleep() 方法不会释放锁,而 wait() 方法会释放锁;
- 再次运行方式不同:
- sleep() 方法导致了程序暂停执行指定的时间,让出 cpu 该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态;
- wait() 只有针对此对象调用 notify() 方法后,本线程才进入对象锁定池准备获取对象锁进入运行状态。
start() 与 run() 的区别
- 作用不用:start() 方法用来启动线程,run() 是线程逻辑的具体方法体;
- 状态不同:调用 start() 方法线程处于就绪状态,并没有运行,run() 执行时,线程处于运行状态。
多线程与并发系列推荐
Java多线程并发02——线程的生命周期与常用方法,你都掌握了吗的更多相关文章
- Java多线程学习(三)---线程的生命周期
线程生命周期 摘要: 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(Running).阻塞 ...
- java 多线程总结篇3之——生命周期和线程同步
一.生命周期 线程的生命周期全在一张图中,理解此图是基本: 线程状态图 一.新建和就绪状态 当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他的Java对象一样,仅仅由Jav ...
- Java学习笔记之——线程的生命周期、线程同步
一. 线程的生命周期 新建(new Thrad):创建线程后,可以设置各个属性值,即启动前 设置 就绪(Runnable):已经启动,等待CPU调动 运行(Running):正在被CPU调度 阻塞(B ...
- Java多线程并发01——线程的创建与终止,你会几种方式
本文开始将开始介绍 Java 多线程与并发相关的知识,多谢各位一直以来的关注与支持.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程的创建方式 在 Java 中,用户常用的主动创建 ...
- Java多线程并发03——在Java中线程是如何调度的
在前两篇文章中,我们已经了解了关于线程的创建与常用方法等相关知识.接下来就来了解下,当你运行线程时,线程是如何调度的.关注我的公众号「Java面典」了解更多 Java 相关知识点. 多任务系统往往需要 ...
- Java多线程并发04——合理使用线程池
在此之前,我们已经了解了关于线程的基本知识,今天将为各位带来,线程池这一技术.关注我的公众号「Java面典」了解更多 Java 相关知识点. 为什么使用线程池?线程池做的工作主要是控制运行的线程的数量 ...
- Java多线程并发05——那么多的锁你都了解了吗
在多线程或高并发情境中,经常会为了保证数据一致性,而引入锁机制,本文将为各位带来有关锁的基本概念讲解.关注我的公众号「Java面典」了解更多 Java 相关知识点. 根据锁的各种特性,可将锁分为以下几 ...
- Java多线程并发07——锁在Java中的实现
上一篇文章中,我们已经介绍过了各种锁,让各位对锁有了一定的了解.接下来将为各位介绍锁在Java中的实现.关注我的公众号「Java面典」了解更多 Java 相关知识点. 在 Java 中主要通过使用sy ...
- Java多线程并发06——CAS与AQS
在进行更近一步的了解Java锁的知识之前,我们需要先了解与锁有关的两个概念 CAS 与 AQS.关注我的公众号「Java面典」了解更多 Java 相关知识点. CAS(Compare And Swap ...
随机推荐
- 分布式事物-2pc和3pc区别
参考地址: https://www.cnblogs.com/bangerlee/p/5268485.html, 感谢原作者 http://blog.51cto.com/11821908/2058651 ...
- C++入门级小算法
反序输出一个整数 #include <iostream> using namespace std; int main() { int n; while (cin >> n)// ...
- Nginx笔记总结十四: nginx反向代理,用内网域名转发
user www www; worker_processes ; error_log logs/error.log; pid logs/nginx.pid; worker_rlimit_nofile ...
- 4.2英寸的iPhone SE2就要来了!但你还会买单吗?
SE2就要来了!但你还会买单吗?" title="4.2英寸的iPhone SE2就要来了!但你还会买单吗?"> 与其他手机厂商不同,苹果在手机市场的产品策略很&q ...
- 如何用js判断一个对象是不是Array
.如何用js判断一个对象是不是Array 1.Array.isArray(obj) 调用数组的isArray方法 2.obj instanceof Array 判断对象是否是Array的实例 3.Ob ...
- python基础修改haproxy配置文件
1.通过eval(),可以将字符串转为字典类型. 2.Encode过程,是把python对象转换成json对象的一个过程,常用的两个函数是dumps和dump函数.两个函数的唯一区别就是dump把py ...
- Mac Webstrom 快捷键
C + D 删除当前行 光标所在行 S + C + F 格式化 S + C + R 重命名 C + { 查找上次 C + } 查找下次 C + S + DE 回到上一次编程位置 C + F 查找 C ...
- 北京VS上海:“活着为了工作”还是“工作为了生活”?
Costco开业你去现场了吗?人口普查似的排队场面对于上海人来说已经不稀奇,毕竟当新鲜的商品或是业态来到中国时,上海常常是第一站.但当Costco的新闻不断发酵的同时,在互联网的角落里也有一群人提出了 ...
- Linux下无法生成core文件的解决办法
1.检查ulimit [root ~]# ulimit -c 0 0:表示禁止生成core文件,此时需要执行ulimit -c unlimited(临时生效),或者在.bashrc中添加“ulimit ...
- MyEclipse下Spring+Hibernate整合
目前,SSH(Struts+Spring+Hibernate)是Web开发的一种常用框架组合,Struts实现了MVC,Hibernate实现了关系对象映射,Spring实现了基于Bean的配置管理. ...