刚开始学线程的时候也是被这几个方法搞的云里雾里的,尤其是一开始看的毕老师的视频,老师一直在强调执行权和执行资格,看的有点懵逼,当然不是说毕老师讲的不好,就是自己有点没听明白,后来复习看了一些其他的博客总结一下线程中的几个容易懵逼的方法以及线程的六种状态。

先来看线程的6种状态,看下面这张图,这张图是在别人博客里面看见的,但是我感觉他的原图有些不完美所以自己重新画了一张图:

先来解释一下这张图,红色字体表示java中的线程的6种状态。当然图也不是很完善,还有LockSupport对象的park/parkNanos/parkUntil方法没有加入进来。

看着这张图,我们再来说说线程中的几个常用方法:

wait方法:在执行wait方法后,当前线程立即释放锁,wait下面的代码不会再执行了。

sleep方法:而线程sleep之后依然持有锁,我睡了你也别想运行。

yield方法:使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里随机选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的。也就是从Running变为Ready,一直在Runnable里面。

join:在B线程里面写threadA.join( ),B挂起,让A运行,看起来B很礼貌让A运行了,但其实B很虚伪,让别人运行又不释放锁。

notify:在执行notify方法后,当前线程不会马上释放该对象锁,呈wait状态的线程也并不能马上获取该对象锁,要等到执行notify方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁,而呈wait状态所在的线程才可以获取该对象锁。

以上大部分知识点都是看的别人博客的或者书里面的,自己做了个总结而已。

其实上面这些东西也不用自己死记,自己写两个线程试试就懂了。我一开始也是为了面试死记硬背,发现老是搞混,后来发现还是得手动敲代码,这样记忆才更加深刻。

说完了上面这些容易让人混淆的方法之后,还有两个容易让人混淆的方法那就是interrupt/interrupted/isInterrupted方法,接下来说说这三个方法,这三个方法都是Thread类中的方法,这三个方法表面看上去很相近,但其实功能差很多。

首先是interrupt方法,中文意思是中断暂停的意思,但千万不要被中文意思所误导,他不能使线程中断或者暂停,我们可以简单的将它理解为一个flag,一开始这个flag默认为false,当我们调用interrupt方法之后这个flag从false变为true,对于正常运行的线程来说没有一点点影响,线程还是照常运行,但是对于处于wait/sleep/join状态中的线程来说,这个变化对于线程影响很大。这个后面再详细说明。

其次是interrupted方法,它的返回值是一个Boolean类型的参数,这个方法的作用是返回当前线程的flag值并且将它重置为false。

最后是isinterrupted方法,它的返回值也是一个Boolean类型的参数,这个方法的作用是仅仅返回当前flag的值。

再来说说为什么interrupt方法对于正常运行的线程来说为什么没有影响而对于处于那三种状态的线程有很大的影响呢,如果我们想用interrupt这个flag来停止线程,那必须得我们自己手动写点什么,例如在run方法中while(Thread.currentThread().isInterrupted),当while循环检测到这个flag变为true之后就会跳出循环从而结束线程。那为什么对于那三种状态的线程来说interrupt方法对他们影响很大呢?

以下内容引自这篇博客:

一.对于wait中等待notify/notifyAll唤醒的线程,其实这个线程已经"暂停"执行,因为它正在某一对象的休息室中,这时如果它的中断状态被改变,那么它就会抛出异常。这个InterruptedException异常不是线程抛出的,而是wait方法,也就是对象的wait方法内部会不断检查在此对象上休息的线程的状态,如果发现哪个线程的状态被置为已中断,则会抛出InterruptedException,意思就是这个线程不能再等待了,其意义就等同于唤醒它了.这里唯一的区别是,被notify/All唤醒的线程会继续执行wait下面的语句,而在wait中被中断的线程则将控制权交给了catch语句.一些正常的逻辑要被放到catch中来运行.但有时这是唯一手段,比如一个线程a在某一对象b的wait中等待唤醒,其它线程必须获取到对象b的监视锁才能调用b.notify()[All],否则你就无法唤醒线程a,但在任何线程中可以无条件地调用a.interrupt();来达到这个目的.只是唤醒后的逻辑你要放在catch中,当然同notify/All一样,继续执行a线程的条件还是要等拿到b对象的监视锁。

二.对于sleep中的线程,如果你调用了Thread.sleep(一年);现在你后悔了,想让它早些醒过来,调用interrupt()方法就是唯一手段,只有改变它的中断状态,让它从sleep中将控制权转到处理异常的catch语句中,然后再由catch中的处理转换到正常的逻辑.同样,地于join中的线程你也可以这样处理。

对于一般介绍多线程模式的书上,他们会这样来介绍:当一个线程被中断后,在进入wait,sleep,join方法时会抛出异常。是的,这一点也没有错,但是这有什么意义呢?如果你知道那个线程的状态已经处于中断状态,为什么还要让它进入这三个方法呢?当然有时是必须这么做的,但大多数时候没有这么做的理由,所以我上面主要介绍了在已经调用这三个方法的线程上调用interrupt()方法让它从这几个方法的"暂停"状态中恢复过来.这个恢复过来就可以包含两个目的:

一.[可以使线程继续执行],那就是在catch语句中执行醒来后的逻辑,或由catch语句转回正常的逻辑.总之它是从wait,sleep,join的暂停状态活过来了。

二.[可以直接停止线程的运行],当然在catch中什么也不处理,或return,那么就完成了当前线程的使命,可以使在上面"暂停"的状态中立即真正的"停止"。

java多线程中wait/notify/sleep/join/yield方法以及多线程的六种状态的更多相关文章

  1. java开发中遇到的问题及解决方法(持续更新)

    摘自 http://blog.csdn.net/pony12/article/details/38456261 java开发中遇到的问题及解决方法(持续更新) 工作中,以C/C++开发为主,难免与其他 ...

  2. 【JAVA】Java 异常中e的getMessage()和toString()方法的异同

    参考链接 CSDN: Java 异常中e的getMessage()和toString()方法的异同 示例代码1: public class TestInfo {     private static ...

  3. Java多线程中wait, notify and notifyAll的使用

    本文为翻译文章,原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example 在Java的Obje ...

  4. 【转】wait,notify,notifyAll,join,yield,sleep的区别和联系

    1.  Thread.sleep(long) 和Thread.yield()都是Thread类的静态方法,在调用的时候都是Thread.sleep(long)/Thread.yield()的方式进行调 ...

  5. [转]wait,notify,notifyAll,join,yield,sleep的区别和联系

    1.  Thread.sleep(long) 和Thread.yield()都是Thread类的静态方法,在调用的时候都是Thread.sleep(long)/Thread.yield()的方式进行调 ...

  6. 彻底理解Python多线程中的setDaemon与join【配有GIF示意】

    在进行Python多线程编程时, join() 和 setDaemon() 是最常用的方法,下面说说两者的用法和区别. 1.join () 例子:主线程A中,创建了子线程B,并且在主线程A中调用了B. ...

  7. java线程学习之notify方法和notifyAll方法

    notify(通知)方法,会将等待队列中的一个线程取出.比如obj.notify();那么obj的等待队列中就会有一个线程选中并且唤醒,然后被唤醒的队列就会退出等待队列.活跃线程调用等待队列中的线程时 ...

  8. Delphi 10.3.1 TNetHttpClient在多线程中存在的问题及解决方法。

    Delphi 10.3.1发布了,对10.3.0存在的各种问题,做了大量的修正.但听高勇说TNetHttpClient在多线程中存在问题,今天做了一下测试,确实如此,看来,还需要官方进一步修正! 具体 ...

  9. 多线程中sleep和wait的区别,以及多线程的实现方式及原因,定时器--Timer

    1.  Java中sleep和wait的区别 ① 这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类. sleep是Thread的静态类方法,谁调用的谁去睡觉,即 ...

随机推荐

  1. iOS 矢量图pdf替换2倍3倍图

    一.在开发中矢量图的使用大大提高设计的切图效率! ios 中可以用pdf替换现在的2倍3倍图(1倍图已经忽略) 1.将pdf矢量图拖进工程Assets.xcassets中 2.按照步骤操作 3.矢量图 ...

  2. Appium+python自动化(十七)- 你难道猴哥失散多年的混血弟弟 - Monkey简介之开山篇(超详解)

    简介 今天由宏哥给小伙伴们来介绍猴哥的混血弟弟=Monkey.Monkey 是Android SDK提供的一个命令行工具, 可以简单,方便地运行在任何版本的Android模拟器和实体设备上. Monk ...

  3. tensorflow学习笔记(1)-环境配置

    配置环境anaconda3+windows10+pycharm+python==3.5.2+tensorflow==1.1.4+cuda10.0+cudnn7 https://www.anaconda ...

  4. OCR文字识别笔记总结

    OCR的全称是Optical Character Recognition,光学字符识别技术.目前应用于各个领域方向,甚至这些应用就在我们的身边,比如身份证的识别,交通路牌的识别,车牌的自动识别等等.本 ...

  5. 使用Kubeadm创建k8s集群之部署规划(三十)

    前言 上一篇我们讲述了使用Kubectl管理k8s集群,那么接下来,我们将使用kubeadm来启动k8s集群. 部署k8s集群存在一定的挑战,尤其是部署高可用的k8s集群更是颇为复杂(后续会讲).因此 ...

  6. 使用c++开发跨平台的程序

    使用c++开发跨平台的程序 背景 在开发过程中,使用c++作为开发语言,通常被认为是痛苦的,啰嗦的,超长开发时间的.最近几年有各种各样的语言被广泛使用,相对比来说c++不是那么出彩.c++虽然年龄大, ...

  7. vue教程(二)--过滤器和监视改动功能

    过滤器filter: 1.将数据进行添油加醋的操作. 2.过滤器分两种: 组件内的过滤器(组件内有效). 全局过滤器 组件内:filters:{过滤器名:过滤器函数fn},fn内通过return 返回 ...

  8. php 排序和置顶功能实现

    (1)排序操作思路 一般来说都是按照发布时间排序.时间戳大的靠前,所以用倒序desc,而不是asc (2)置顶操作思路: 点击置顶时,修改数据库addtime字段值为当前时间即可.因为排序是按照时间戳 ...

  9. Initialization failed for 'https://start.spring.io' Please check URL

    错误描述:Initialization failed for 'https://start.spring.io' Please check URL, network and proxy setting ...

  10. java.sql.SQLException: Parameter index out of range (0 < 1 ).

    向SQL中传入数据是从1开始的!!! 从ResultSet中取数据也是从1开始的!