javaEE——线程的等待和结束

文章目录

  • Thread 类及常见方法
    • 启动一个线程
    • 中断一个线程
      • 变量型中断
      • 调用 interrupt() 方法来通知
      • 观察标志位是否被清除
    • 等待一个线程
    • 获取当前线程引用
    • 休眠当前线程
  • 线程的状态
    • 观察线程的所有状态
      • 观察 1: 关注 NEW 、 RUNNABLE 、 TERMINATED 状态的切换
  • 多线程带来的风险
    • 为什么会这样?

Thread 类及常见方法

Thread类是我java给提供的一个线程类其内部包含了很多帮助我们的方法。除了上次讲述的初始化方法外还有哪些呢?请看下面的内容

启动一个线程

我们知道了通过复写run方法创建一个线程对象(在我的上一篇文章中说明过)但是线程被创建出来并不代表线程已经开始了运行。因此只有调用了start方法才是真正的创建了一个线程用法如下

public class Main {public static void main(String[] args) throws InterruptedException{Thread t=new Thread(()->{while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("我是lambda表达式创建出的线程");}});t.start();while(true){Thread.sleep(1000);System.out.println("Hello world!");}}
}

中断一个线程

线程在执行的过程中不仅要知道如何进行启动,中断也同样重要因为线程的执行只有当线程这个任务彻底完成后才会中断但是这个机制是不好的因为这时候就会导致一些有问题的线程我们没法立刻进行中断,那么现在主要有哪些中断线程的方法呢?

变量型中断

使用一个自定义变量进行中断线程请看如下代码

class Mythread extends Thread{public void run(){while(Main.flag){try {sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正常交易中");}System.out.println("有内鬼停止交易");}
}
public class Main {public static boolean flag=true;public static void main(String[] args) throws InterruptedException{Thread t=new Mythread();t.start();int cnt=0;while(true){Thread.sleep(1000);if(cnt<5)System.out.println("令线程正常交易");cnt++;if(cnt>=5){System.out.println("通知线程有内鬼");flag=false;break;}}}
}

请看上面这个代码这个代码很明显就是用了一个flag变量来控制这里面的while循环是否可以继续执行但是这个方法非常的不优雅,感觉有种很土的感觉,那难道我们的java就没有官方提出来一些方法来使用嘛?当然是有的。那就是下面三个方法

调用 interrupt() 方法来通知

方法说明
public void interrupt()中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted()判断当前线程的中断标志位是否设置 调用后清除标志位
public boolean isInterrupted()判断对象关联线程的标志位是否设置调用后不清除标志位

那么这些方法该怎么使用呢?请看如下代码

class Mythread extends Thread{public void run() {while(!Thread.interrupted()){try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("正常交易中");}System.out.println("有内鬼停止交易");}
}
public class Main {public static boolean flag=true;public static void main(String[] args) throws InterruptedException{Thread t=new Mythread();t.start();int cnt=0;while(true){Thread.sleep(1000);if(cnt<5)System.out.println("令线程正常交易");cnt++;if(cnt>=5){System.out.println("通知线程有内鬼");t.interrupt();break;}}}
}

在这里插入图片描述
在这个代码运行截图中我们可以看到即使抛出了异常但是这个代码仍然没有终止那么这是为什么呢?因为我们看一下上面的对这些的方法的介绍。interrupted()方法介绍说了调用本方法可以查看此时的标志位并且在查看过后就会清除标志位,那么按照这个代码的逻辑我们来看一下。首先我们调用了interrupt()方法设置了我们的标记位,并且检测到线程此时正在休眠因此我们以异常的形式进行了抛出,之后当调用interrupted()方法进行判断的时候此时标志位未被设置因此循环将会继续执行,那么难道就没有办法了吗?当然是有的,第一个办法就是将异常抛出(因为我们学过当我们将异常抛出的时候那么这个方法就不会继续往后执行了)(第二个办法就是在循环内部加一个break)
thread 收到通知的方式有两种:

  1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通
    知,清除中断标志
    当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择
    忽略这个异常, 也可以跳出循环结束线程.
  2. 否则,只是内部的一个中断标志被设置,thread 可以通过
    Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
    Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

观察标志位是否被清除

观察标志位是否被清除,我们来讲述一下那两个方法

首先标志位大家可以理解是什么呢?其实就是我们第一种方法定义的一个boolean的变量一样那么清除标志位就相当于把这个标志位重新设置成了false那样子,设置标志位就相当于将其设置为true,那么带着这种理解我们来看一下这两种方法首先是public static boolean interrupted()这个方法就像是一个自动开关一样,当你检查的时候相当于把灯打开了,当你检查完毕后又把灯给重新随手关上了public boolean isInterrupted()而这个则是不会关闭。

等待一个线程

等待一个线程,什么是等待一个线程呢?其实就是等待一个线程结束,我们刚刚说过线程是并发执行的,但是有些时候我们希望这个线程是顺序的,有时又可以是并发那么该怎么做呢?那就需要线程的等待了。顾名思义线程的等待其实就是等待一个线程的任务进行完毕后再去执行接下来的代码,因此就实现了线程的顺序执行,那么该怎么完成呢?那就是用join方法请看下面的代码


class Mythread extends Thread{public void run() {int i=0;while(i<=6){try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();break;}i++;System.out.println("正常交易中");}//System.out.println("有内鬼停止交易");}
}
public class Main {public static boolean flag=true;public static void main(String[] args) throws InterruptedException{Thread t=new Mythread();t.start();t.join();System.out.println("线程已经结束");}
}

代码运行截图
在这里插入图片描述
这样我们就可以看的很清楚了线程是顺序执行的。

获取当前线程引用

这个方法就比较简单了可以了解一下代码如下

public class Main {public static boolean flag=true;public static void main(String[] args) throws InterruptedException{Thread t=Thread.currentThread();System.out.println(t);}
}

休眠当前线程

休眠当前线程其实就是我们用的sleep方法关于这个方法呢我们要知道实际的休眠时间是要大于你设置的休眠时间的。

线程的状态

线程的状态是一个枚举类型,Thread.State,那么都有哪些状态呢?我们来看一下以下代码

public class Main {public static boolean flag=true;public static void main(String[] args) throws InterruptedException{for(Thread.State state:Thread.State.values()){System.out.println(state);}}
}

在这里插入图片描述
那么我们接下来,来描述以下现成的 这些状态的含义

状态类型状态的含义
NEW线程被创建出来但并没有开始行动
RUNNABLE可以工作的又分为正在工作或者即将开始工作
BLOCKED排队等着其他的事情
WAITING排队等着其他的事情
TIMED_WAITING排队等待其他的事情
TERMINATED工作已经完成

观察线程的所有状态

观察 1: 关注 NEW 、 RUNNABLE 、 TERMINATED 状态的切换

使用isAlive进行线程状态的观察


public class Main {public static boolean flag=true;public static void main(String[] args) throws InterruptedException{Thread t=new Thread(()->{for(int i=0;i<5;i++){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正在运行中");}});t.start();while(true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(t.getState());}}
}

在这里插入图片描述
在运行截图中我们可以看到这里的线程状态有的时候是TIMED_WAITING有时候却又变成了RUNNABLE那么这是为什么会这样呢?真的是非常的奇怪其实原因很简单因为我们加的有sleep语句当我们调用state方法进行查看此时线程的状态的时候那么这个线程可能正在执行任务也有可能是正在sleep因此才会出现这种现象

多线程带来的风险

首先多线程会带来怎样的风险呢?我们来看一下下面的这个例子

class MyRun{public  int run=0;public void Run(){run++;}
}
public class Main {public static boolean flag=true;public static void main(String[] args) throws InterruptedException{final MyRun m=new MyRun();Thread t1=new Thread(()->{for (int i=0;i<5000;i++)m.Run();System.out.println("t1执行完毕"+m.run);});Thread t2=new Thread(()->{for (int i=0;i<5000;i++)m.Run();System.out.println("t2执行完毕"+m.run);});t1.start();t2.start();t1.join();t2.join();System.out.println(m.run);}
}

他的运行结果是怎么样的呢看下图
在这里插入图片描述
另外我在写代码的时候有一个非常傻子的错误那就是把join没写上导致打印结果是0这里原因是因为忽略了线程的并发执行,有同样问题的同学可以共勉。

为什么会这样?

为什么会这样呢?按道理来说不应该是一万吗?为什么会发生这种情况呢?相信大部分同学都会冒出这样的疑问那么这是为什么呢?其实原因很简单因为对于++来说你看到的是一个操作其实他的底层是三个指令也就是三个操作正因为是三个操作这就导致了这个操作不是原子的,那么就可能出现我们数据库中类似于脏读的情况。那么剩下的内容我会在下一期文章中详细说明

	希望往后的日子可以与所爱万般皆顺利。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2869134.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

基于SpringBoot框架实现的B2B平台的医疗病历交互系统

采用技术 基于SpringBoot框架实现的B2B平台的医疗病历交互系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 管理员角色 医院管理 医院注册 医院文…

pytorch 入门基础知识一(Pytorch 01)

一 深度学习基础相关 深度学习三个主要的方向&#xff1a;计算机视觉&#xff0c;自然语言&#xff0c;语音识别。 机器学习核心组件&#xff1a;1 数据集(data)&#xff0c;2 前向传播的model(net)&#xff0c;3 目标函数(loss)&#xff0c; 4 调整模型参数和优化函数的算法…

C#混淆心得

C#混淆心得 近期遇到混淆C#代码的需求&#xff0c;在网上找了很多办法&#xff0c;在此记录一下。 混淆的本质就是让代码变丑&#xff0c;让别人看不懂。 为什么要混淆&#xff1a; 1.保护核心代码 可以在一定程度上避免别人偷代码&#xff0c;从而保护重要的部分&#xf…

vscode jupyter 如何关闭声音

网上之前搜的zen模式失败 仅仅降低sound失败 #以下是成功方式&#xff1a; 首先确保user和remote的声音都是0&#xff1a; 然后把user和remote的以下设置都设置为off就行了&#xff01; 具体操作参考 https://stackoverflow.com/questions/54173462/how-to-turn-off-or-on-so…

传输层/UDP/TCP协议

再谈端口号 TCP/IP协议用“源IP”&#xff0c;“源端口号”&#xff0c;“目的IP”&#xff0c;“目的端口号”&#xff0c;“协议号”&#xff0c;这样一个五元组来标识一个通信&#xff08;可以用netstat -n来查看&#xff09;。 端口号的划分和知名端口号 我们之前就说过&am…

综合知识篇05-设计模式考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…

【Java】容器|Set、List、Map及常用API

目录 一、概述 二、List 1、List的常用API 2、ArrayList 3、List遍历 三、Set 1、Set的常用方法: 2、HashSet 3、遍历集合&#xff1a; 四、Map 1、Map常用API 2、HashMap 3、遍历Map 五、迭代器 一、概述 在Java中所有的容器都属于Collection接口下的内容 1…

如何监控用户对网站的操作行为?

需求&#xff1a; 1、对所有用户的操作进行监控&#xff0c;包括用户行为的录制 2、通过用户操作热度地图&#xff0c;来监控每个功能的使用频率&#xff0c;从而来决策产品的下一步迭代 一、浏览器自带的录频方法 MediaDevices.getUserMedia() 二、html2canvas页面截屏方法 …

2022年安徽省职业院校技能大赛 (高职组)“云计算”赛项样卷

#需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; 第一场次&#xff1a;私有云(5…

cool 中的Midway ----node.js的TypeORM的使用

1.介绍 TypeORM | Midway TypeORM 是 node.js 现有社区最成熟的对象关系映射器&#xff08;ORM &#xff09;。本文介绍如何在 Midway 中使用 TypeORM 相关信息&#xff1a; 描述可用于标准项目✅可用于 Serverless✅可用于一体化✅包含独立主框架❌包含独立日志❌ 和老写…

展开说说:Android之SharedPreferences

SharedPreferences 是一种轻量级的数据持久化存储机制。以key/value键值对形式存储在xml文件&#xff0c;用于保存一些应用程序数据。保存在 /data/data/PACKAGE_NAME/shared_prefs/xxx.Xml文件。 SharedPreferences 只能存储string&#xff0c;int&#xff0c;float&#xff…

F5怎么样?保障AI服务的安全性和交付

伴随着人工智能时代的快速发展&#xff0c;AI已成为企业数字化转型的得力工具&#xff0c;比如为用户提供更好的服务&#xff0c;降低企业成本等。与此同时&#xff0c;AI技术的应用也会带来应用安全等方面的新风险&#xff0c;可见其有着双刃剑效应。作为一家提供多云应用安全…

【时事篇-05-03】20240316 一笔145元拆分成3笔存款存入(排除有相似性的十位数字)

背景需求 前文提到&#xff0c;每笔都存一样的数目&#xff0c;容易被银行识别违法&#xff0c; 【时事篇-05-01】20240112 150元存46只货币基金-CSDN博客文章浏览阅读580次&#xff0c;点赞15次&#xff0c;收藏11次。【时事篇-05-01】20240112 150元存46只货币基金https://…

LCD屏的应用

一、LCD屏应用 Linux下一切皆文件&#xff0c;我们的LCD屏再系统中也是一个文件&#xff0c;设备文件&#xff1a;/dev/fb0。 如果要在LCD屏显示数据&#xff0c;那我们就可以把数据写入LCD屏的设备文件。 1.显示颜色块 LCD屏分辨&#xff1a;800*480 像素 32位:说明一个像…

创新指南|制药行业如何拥抱生成式AI在新药发现与开发中突破获益

生成式AI在药物发现中的应用可加速药物研发过程&#xff0c;并可能降低成本。通过利用GenAI&#xff0c;制药公司能在早期药物发现和开发中实现更快的成果&#xff0c;这包括从目标识别、验证&#xff0c;到优化的多个环节。 AI有潜力在药物筛选和优先排序、目标识别及验证、药…

书客护眼落地灯销量火爆,售罄、补货、又断货、再补货!又成断货王!

今日&#xff0c;备受关注的书客Sun护眼大路灯在市场上掀起了一股抢购热潮&#xff0c;作为近年来照明领域中最大的黑马品牌&#xff0c;始终坚持并最求技术创新的书客品牌&#xff0c;在近日发布全新系列落地护眼台灯后&#xff0c;不仅备受消费者青睐&#xff0c;更是成为了新…

spacy进行简单的自然语言处理的学习

自然语言处理基本概念 概念&#xff1a;自然语言处理&#xff0c;是让机器理解人的语言的过程。 作用&#xff1a;通过使用自然语言处理&#xff0c;机器可以理解人的语言&#xff0c;从而进行语义分析&#xff0c;例如&#xff1a;从一句话中判断喜怒哀乐&#xff1b;从一段文…

MongoDB——linux中yum命令安装及配置

一、创建mongodb-org-3.4.repo文件 vi /etc/yum.repos.d/mongodb-org-3.4.repo 将下面内容添加到创建的文件中 [mongodb-org-3.4] nameMongoDB Repository baseurlhttps://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.4/x86_64/ gpgcheck1 enabled1 gpgkeyhttps://www…

【Docker篇】自定义Dockerfile的操作

文章目录 &#x1f354;镜像结构&#x1f6f8;什么是Dockerfile⭐基于Ubuntu镜像构建一个新镜像&#xff0c;运行一个java项目&#x1f50e;使用 java:8-alpine &#x1f354;镜像结构 镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。 我们以MySQL为例&am…

【PyTorch】基础学习:在终端中打印当前虚拟环境下的Pytorch版本信息

【PyTorch】基础学习&#xff1a;在终端中打印或查看当前虚拟环境下的Pytorch版本信息 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程…