前言
最近看到很多人都在讨论多线程的问题,于是写出了这篇博客,希望可以帮到正在学习和使用这块的朋友们,首先我们先看看两个图(两个图都来自其他码农的分享)
这两个图是一样的逻辑,这里一起罗列出来,下面让我们用语句来简单描述下两个图:
sleep 让线程从 【running】 -> 【阻塞态】 时间结束/interrupt -> 【runnable】
wait 让线程从 【running】 -> 【等待队列】notify -> 【锁池】 -> 【runnable】
当我们看到这个图的时候首先会看到线程的几种状态,下面让我们先来分别说明一下:
线程共包括一下5种状态:
1,新建、初始状态(New) :线程对象被创建后就进入了新建状态,Thread thread = new Thread();
2,就绪(Runnable):也被称之为“可执行状态”,当线程被new出来后,其他的线程调用了该对象的start()方法,即thread.start(),此时线程位于“可运行线程池”中,只等待获取CPU的使用权,随时可以被CPU调用。进入就绪状态的进程除CPU之外,其他运行所需的资源都已经全部获得。
3,运行(Running):线程获取CPU权限开始执行。注意:线程只能从就绪状态进入到运行状态。
4,阻塞(Bloacked):阻塞状态是线程因为某种原因放弃CPU的使用权,暂时停止运行,知道线程进入就绪状态后才能有机会转到运行状态。
阻塞的情况分三种:
(01) 等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池中”。进入这个状态后是不能自动唤醒的,必须依靠其他线程调用notify()或者notifyAll()方法才能被唤醒。
(02)同步阻塞:运行的线程在获取对象的(synchronized)同步锁时,若该同步锁被其他线程占用,则JVM会吧该线程放入“锁池”中。
(03)其他阻塞:通过调用线程的sleep()或者join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新回到就绪状态
以上三种阻塞状态请参考上面的2个图示来理解
5,死亡(Dead):线程执行完了或因异常退出了run()方法,则该线程结束生命周期。
wait(), notify(), notifyAll()等方法介绍
这三个方法都是定义到Object类中,wait的作用是当当前线程释放它所持有的锁进入等待状态,而notify和notifyAll则是唤醒当前对象上的等待线程。
notify() -- 唤醒在此对象监视器上等待的单个线程。
notifyAll() -- 唤醒在此对象监视器上等待的所有线程。
wait() -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout, int nanos) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。
wait()会使“当前线程”等待,并且会释放到它所占用的“锁标志”,从而使线程所在对象中的其他synchronized数据可以被其他线程使用。
suspend()和 resume()方法
sleep() 和 yield()方法
这两个方法都定义在Thread.java中
sleep()的作用是让当前线程休眠(正在执行的线程主动让出cpu,然后cpu就可以去执行其他任务),即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间,线程休眠的时候会大于或者等于该休眠时间,当时间过后该线程重新被会形式,他会由“阻塞状态”编程“就绪状态”,从而等待cpu的调度执行,注意:sleep方法只是让出了cpu的执行权,并不会释放同步资源锁。
yield()的作用是让步,它能够让当前线程从“运行状态”进入到“就绪状态”,从而让其他等待线程获取执行权,但是不能保证在当前线程调用yield()之后,其他线程就一定能获得执行权,也有可能是当前线程又回到“运行状态”继续运行,注意:这里我将上面的“具有相同优先级”的线程直接改为了线程,很多资料都写的是让具有相同优先级的线程开始竞争,但其实不是这样的,优先级低的线程在拿到cpu执行权后也是可以执行,只不过优先级高的线程拿到cpu执行权的概率比较大而已,并不是一定能拿到。
举个例子:一帮朋友在排队上公交车,轮到Yield的时候,他突然说:我不想先上去了,咱们大家来竞赛上公交车。然后所有人就一块冲向公交车,
有可能是其他人先上车了,也有可能是Yield先上车了。
但是线程是有优先级的,优先级越高的人,就一定能第一个上车吗?这是不一定的,优先级高的人仅仅只是第一个上车的概率大了一点而已,
最终第一个上车的,也有可能是优先级最低的人。并且所谓的优先级执行,是在大量执行次数中才能体现出来的。
wait和sleep的区别
相同点:
1,他们都是在多线程的环境下,都可以在程序的调用出阻塞指定的毫秒数并且返回
2,两个方法都可以通过interrupt()方法打断线程的暂停状态,但是线程会抛出InterruptedException。需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用 interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出InterruptedException 。
不同点:
1,Thread类的方法:sleep(),yield()
Object的方法:wait()和notify()、notifyAll()
2,每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。 sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3, wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用 。注意:wiat()必须放在synchronized block中,否则会在program runtime时扔出“java.lang.IllegalMonitorStateException”异常。
4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
综上可得两者最大的区别:sleep()睡眠时,保持对象锁,仍然占有该锁;而wait()睡眠时,释放对象锁。
注意:
第一:调用notify() 方法导致解除阻塞的线程是从因调用该对象的 wait()方法而阻塞的线程中随机选取的,我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。
第二:除了notify(),还有一个方法 notifyAll()也可起到类似作用,唯一的区别在于,调用 notifyAll()方法将把因调用该对象的 wait()方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。
谈到阻塞,就不能不谈一谈死锁,略一分析就能发现,suspend()方法和不指定超时期限的wait()方法的调用都可能产生死锁。遗憾的是,Java并不在语言级别上支持死锁的避免,我们在编程中必须小心地避免死锁。
java线程状态 以及 sheep()、wait()、yield() 区别的更多相关文章
-
Java线程状态及 wait、sleep、join、interrupt、yield等的区别
Java中的线程状态(详见Java线程状态及转换-MarchOn): wait:Object类的实例方法,释放CPU执行权,进入等待状态,直到 被中断.被拥有该对象锁的线程唤醒(notify或not ...
-
java线程中的sleep和wait区别
面试题:java线程中sleep和wait的区别以及其资 ...
-
Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程
下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...
-
Java线程状态及同步锁
线程的生命历程 线程的五大状态 创建状态:简而言之,当创建线程对象的代码出现的时候,此时线程就进入了创建状态.这时候的线程只是行代码而已.只有调用线程的start()方法时,线程的状态才会改变,进入就 ...
-
Java线程状态切换以及核心方法
1.Java线程状态 1.1 线程主要状态 ①初始(NEW):新创建了一个线程对象,但还没有调用start()方法.②运行(RUNNABLE):Java线程中将就绪(ready)和运行中(runnin ...
-
面试官:都说阻塞 I/O 模型将会使线程休眠,为什么 Java 线程状态却是 RUNNABLE?
摘要: 原创出处 https://studyidea.cn 「公众号:程序通事 」欢迎关注和转载,保留摘要,谢谢! 使用 Java 阻塞 I/O 模型读取数据,将会导致线程阻塞,线程将会进入休眠,从而 ...
-
浅谈 Java线程状态转换及控制
线程的状态(系统层面) 一个线程被创建后就进入了线程的生命周期.在线程的生命周期中,共包括新建(New).就绪(Runnable).运行(Running).阻塞(Blocked)和死亡(Dead)这五 ...
-
Java线程状态及切换
Java线程状态及切换 一.什么是Java线程状态 在Java程序中,用于描述Java线程的六种状态: 新建(NEW):当前线程,刚刚新建出来,尚未启动. 运行(RUNNABLE):当前线程,处于竞争 ...
-
Java线程状态介绍
原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11867086.html Java 线程状态介绍: Java官方文档中对Java线程的几种状态做 ...
随机推荐
-
spring 整合 mongo
spring 非常强大,不仅在jdbc访问提供了jdbctemplate,而且在mongo访问上提供了mongoTemplate.闲话不多说,下边开始整合mongoTemplate. ONE: 添加s ...
-
.net的一些新语法的整理
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...
-
分享:大晚上用自己的锤子手机跨系统刷MIUI,跌宕起伏啊!!
序言: 写这篇博客之前问了一下博客园官方,能不能写关于刷机这一方面的,官方还是比较通情达理的,说技术类没有限制的,那样我就放心的写了.今天早上在博客园中稍微逛了一下,感觉似乎很少有关于刷机这一方面的, ...
-
java 以及 vs 的快捷键
javactrl+shift+y 小写ctrl+shift+x 大写ctrl+shift+f 格式化代码 vsctrl+u 小写ctrl+shift+u 大写ctrl+k+f 格式化代码
-
1.4.9 DocValues
DocValues 在solr4.2以后,引入了一个令人兴奋的功能,这个功能在lucene存在已经一段时间了,但是还没有在solr中使用. 在某些方面,DocValue 是一种非常有效的索引方式. 为 ...
-
采用WindowManager添加您自己的自定义视图
原文地址:使用WindowManager加入自己定义视图 在写手机卫士的时候,用户拨打|接听电话须要显示号码归属地,然后出现了一些异常.在此留下记号,希望对麻友们有帮助: BUG教程 在使用 view ...
-
Python3基础 setdefault() 根据键查找值,找不到键会添加
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...
-
Sqlserver批量生成10w不重复8位数字
项目中需要批量生成100W不重复的8位数,百度了一大把,修改成了如下Sql,做下笔记,希望对看到的朋友有帮助(下面是生成10W条,条数自己改,性能还可以) 表名:makeExtensionCode 字 ...
-
Apollo 2 如何支持 @Value 注解自动更新
前言 Apollo 在 v0.10.0 版本后,支持自动更新.v0.10.0之前的版本在配置变化后不会重新注入,需要重启才会更新. 也就是说,如果一个属性加入了 @Value 注解,并且这个配置在配置 ...
-
在ASP.NET里实现计算器代码的封装
一.具体代码 Default2.aspx.cs public partial class Chapter1_Default2 : System.Web.UI.Page { protected void ...