当前位置: 首页 > news >正文

【JavaEE】多线程(二)

多线程(二)

文章目录

  • 多线程(二)
    • 第一个多线程程序
    • 观察线程
    • sleep
    • 创建线程
      • 继承Thread类,重写run方法
      • 实现Runnable, 重写run
      • 继承Thread,重写run
      • 实现Runnable,重写run
      • 基于lambda表达式
    • Thread的常见构造方法
      • Thread几个常见属性
        • setDaemon();
        • isAlive();

续上文, 多线程(一),我们可以了解到,多线程和普通程序的区别:

  • 每一个程序都是一个独立的执行流
  • 多个线程之间都是“并发”执行的

第一个多线程程序

class MyTread extends Thread{@Overridepublic void run() {//这个方法就是线程的入口方法while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello thread");}}
}//演示创建线程
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread t = new MyTread();//start 和 run 都是 Thread 的成员//run 只是描述了线程的入口(线程主要做什么任务)//start 则是真正调用了系统API,在系统中创建线程,让线程再调用run//t.start();//t.run();t.start();while (true){System.out.println("hello main");Thread.sleep(1000);}}
}

通过运行这个程序,我们可以发现两个while循环在“同时执行”,可以看到打印结果是两边的日志在交替打印的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这也说明了:

每个线程都是一个独立执行的逻辑,也就是独立的执行流~

我们也可以形象的看作是:兵分两路,并发执行~

并发 => 并行 + 并发 => 并发编程的效果 => 充分使用多核cpu资源

不过当我们将main 函数的t.start();改成t.run();

public static void main(String[] args) throws InterruptedException {Thread t = new MyTread();//start 和 run 都是 Thread 的成员//run 只是描述了线程的入口(线程主要做什么任务)//start 则是真正调用了系统API,在系统中创建线程,让线程再调用runt.run();while (true){System.out.println("hello main");Thread.sleep(1000);}}

此时,代码中不会创建新的线程,就只有一个主线程,这个主线程只能依次执行循环,执行完一个在执行另外一个~,不过因为代码中是while(true),是不会循环结束的,所以代码也就无法走到hello main了。

还有一个需要我们了解的:main这个线程是jvm自动创建的,和其他线程比起来并没有什么特殊的,在一个java进程中,至少都会有一个main线程。


观察线程

当我们多线程程序运行的时候,我们可以使用IDEA或者jconsole来观察该进程内的多线程情况~

这里我们主要介绍jconsolejconsolejdk自带的程序

jconsole我们可以在jdk包里找到

  1. 首先我们要先找到jdk的安装地址

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  2. 在地址处找到jdk然后打开bin目录,然后再列表中找到jconsole.exe

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里我们要注意的是:

  • 在启动jconsole.exe之前,我们得确保IDEA的程序已经跑起来了

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

sleep

上述的线程,我觉得他在while循环中转的太快了,想要他慢点~

那我们就可以使用Thread.sleep();,sleepThread静态方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

需要注意的是:我们使用sleep的时候汇报这样的错误

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MyRunnable里的异常是受查异常,必须要显示处理,此处必须try catch,不能用throws,在这个代码中是重写父类的run,父类的run没有throws,子类方法也就不能也有。

而这个程序每秒所打印出来的内容,顺序都是不确定的。

因为这两线程都是休眠1000ms,当时间到后,谁先谁后是不一定的,这个过程可以视为“随机”

操作系统,对于多个线程的调度顺序,是不确定,随机的,而此处的随机不是数学上的概率均等的随机,是取决于 操作系统 对于线程调度的模块(调度器)来具体实现的~

创建线程

继承Thread类,重写run方法

package Thread.test_8_12;
class MyTread extends Thread{@Overridepublic void run() {//这个方法就是线程的入口方法while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello thread");}}
}//演示创建线程
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread t = new MyTread();//start 和 run 都是 Thread 的成员//run 只是描述了线程的入口(线程主要做什么任务)//start 则是真正调用了系统API,在系统中创建线程,让线程再调用run//t.start();//t.run();t.start();while (true){System.out.println("hello main");Thread.sleep(1000);}}
}

实现Runnable, 重写run

package Thread.test_8_12;
class MyRunnable implements Runnable{@Overridepublic void run() {while (true) {System.out.println("hello world");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class Demo2 {public static void main(String[] args) throws InterruptedException {Runnable runnable = new MyRunnable();Thread t = new Thread(runnable);t.start();while (true){System.out.println("hello main");Thread.sleep(1000);}}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

好处

使用Runnable的写法,和直接继承Thread之间的区别就是:解耦合

使用Runnable接口重写run方法相对于直接继承Thread类的方式更加灵活、可扩展,并且能够实现解耦合。我们可以将任务逻辑与线程的实现分离,通过实现Runnable接口,我们能够更好地控制线程的行为并在需要时更好地管理和复用线程。


这里我们举个例子:

你老婆想要喝水,但是她又懒得去接水,于是她就会叫你或者你5岁孩子去接水。

而接水就是一个任务,你执行还是你孩子执行,这是没有本质区别的,那么此时我们就可以将接水这个任务单独提取为Runnable,后续是谁都可以轻轻松松完成这个任务~

但是如果任务变了呢?接水 -> 泡茶

那么此时这个任务就只能你来完成了,你那5岁孩子完成不来任务

那么这个任务就是和你这个线程有一定耦合关系的~


而我们创建一个线程,需要进行两个关键操作:

  1. 明确线程要执行的任务

    任务本身,不一定和线程 概念 强相关的

    • 这个任务只是单纯的执行一段代码,这个任务是使用单个线程执行还是多个线程执行,亦或是别的方式(信号处理函数/协程/线程池)都没什么区别~
    • 任务本身,就可以将任务本身提取出来,此时就可随时把代码改成使用其他方式来执行这个任务~
  2. 调用系统的 api 创建线程


继承Thread,重写run

package Thread.test_8_12;
public class Demo3 {public static void main(String[] args) {//匿名内部类Thread t = new Thread(){@Overridepublic void run() {while (true){System.out.println("hello world");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}};t.start();while (true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

**外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
**

实现Runnable,重写run

package Thread.test_8_12;
public class Demo4 {public static void main(String[] args) {Runnable runnable = new Runnable() {@Overridepublic void run() {while (true) {System.out.println("hello world");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}};Thread t = new Thread(runnable);t.start();while (true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

基于lambda表达式

package Thread.test_8_12;
public class Demo6 {public static void main(String[] args) {Thread t = new Thread(()->{while (true){System.out.println("hello world");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();while (true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

那为什么lambda表达式不用重写run方法?
实际上啊,lambda自身就是run方法

  • lambda:本身就是用来表示逻辑的,使用lambda就能描述出当前的线程要干嘛
  • run方法:线程的入口,通俗来说就是:告诉线程你要干啥子~

Thread的常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用Runnable对象创建线程对象,并命名
Thread(TreadGroup group, Runnable target)线程可以被用来分组管理,分好的几位线程组

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

public class Demo7 {public static void main(String[] args) {Thread t = new Thread(() -> {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}, "这是一个新线程");t.start();}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Thread几个常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台进程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

setDaemon();

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一般默认下,一个进程是前台线程~

public static void main(String[] args) {Thread t = new Thread(() -> {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}, "这是一个新线程");//设置 t 为后台线程t.setDaemon(true);t.start();}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

调用setDaemon(true)方法,将t设置为后台线程。后台线程是一种特殊的线程,当所有前台线程(例如主线程)都结束时,后台线程会自动终止

改成后台线程之后,主线程飞快执行完了,此时就没有其他前台线程了,于是线程结束,t线程来不及执行,就 over 了~~


isAlive();

Thread 对象的生命周期,要比系统内核中的线程更长一些~

Thread对象还在,内核中的线程已经销毁了这样的情况(不求同年同月同日生,也不求i同年同月同日死)

所以我们可以使用isAlive();来判定内核线程是不是已经没了,也就是回调函数执行完毕,线程就没了

package Thread;
public class Demo8 {public static void main(String[] args) {Thread t = new Thread(()->{System.out.println("线程开始");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程结束");});t.start();System.out.println(t.isAlive());try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(t.isAlive());}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


下面用一张图概括一下本篇文章所讲的内容~

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

至此,多线程(二)先写到这,后续会持续更新,敬请期待~

相关文章:

【JavaEE】多线程(二)

多线程(二) 文章目录 多线程(二)第一个多线程程序观察线程sleep创建线程继承Thread类,重写run方法实现Runnable, 重写run继承Thread,重写run实现Runnable,重写run基于lambda表达式 T…...

OkHttp 根据服务器返回的的过期时间设置缓存

据返回的缓存时间来缓存响应,可以通过使用OkHttp的CacheControl和ResponseCacheInterceptor来实现。以下是一个示例代码: // 创建缓存目录和缓存对象 File cacheDirectory new File(context.getCacheDir(), "http-cache"); int cacheSize 1…...

智能远程监考方案助力企业考试化繁为简

在音视频数字化之旅中,轻装上阵。 近年来,在数字化浪潮之下,远程考试频繁成为各领域热词,各企业也纷纷改革求新,将原本的企业内部考试转移到线上,从而获取更低廉的组考成本,更高的管理效率&…...

基于matlab实现的额 BP神经网络电力系统短期负荷预测未来(对比+误差)完整程序分享

基于matlab实现的额 BP神经网络电力系统短期负荷预测 完整程序: clear; clc; %%输入矢量P(15*10) P[0.2452 0.1466 0.1314 0.2243 0.5523 0.6642 0.7105 0.6981 0.6821 0.6945 0.7549 0.8215 0.2415 0.3027 0; 0.2217 0.1581 0.1408 0.23…...

WPF的_Expander控件

WPF Expander 是 WPF(Windows Presentation Foundation)框架中的一个控件,用于实现可以展开和折叠内容的可折叠面板。 Expander 控件通常由一个展开/折叠的标题(Header)和一个显示/隐藏的内容部分(Content…...

【MT7628AN】IOT | MT7628AN OpenWRT开发与学习

IOT | MT7628AN OpenWRT开发与学习 时间:2023-06-21 文章目录 `IOT` | `MT7628AN` `OpenWRT`[开发与学习](https://blog.csdn.net/I_feige/article/details/132911634?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22132911634…...

基于Matlab实现自动泊车(垂直泊车)

自动泊车是一项非常有趣和实用的技术,它可以让车辆在没有人为干预的情况下自动停放在合适的位置上。在这篇文章中,我们将介绍如何使用Matlab实现自动泊车。 首先,我们需要了解自动泊车的基本原理。自动泊车系统通常包括车辆、传感器和控制算…...

笔试面试相关记录(4)

(1)实现防火墙的主流技术有哪些? 实施防火墙主要采用哪些技术 - 服务器 - 亿速云 (yisu.com) (2) char arr[][2] {a, b, c, d}; printf("%d", *(arr1)); 输出的是谁的地址?字符c 测试代码如下…...

unity UDP 通信

客户端 接收端 : using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using UnityEngine; using UnityEngine.UI;public cla…...

一篇解决JavaScript

华子目录 JavaScript介绍JavaScript的组成JavaScript书写位置内部外部 js注释js输入(prompt)js输出js变量js基本数据类型number(数值类型)string(字符串)Boolean(布尔类型)undefined…...

Unity UGUI(一)基础组件

文章目录 1.Text:文本框2.Image:精灵图3.RawImage:生图4.Button:按钮5.InputField:输入框6.Tooggle:选择框7.Slider:滑动条8.Dropdown:下拉菜单9.Scrollbar:滚动条10.Scr…...

【微服务】六. Nacos配置管理

6.1 Nacos实现配置管理 配置更改热更新 在nacos左侧新建配置管理 Data ID:就是配置文件名称 一般命名规则:服务名称-环境名称.yaml 配置内容填写:需要热更新需求的配置 配置文件的id:[服务名称]-[profile].[后缀名] 分组&#…...

【华为云云耀云服务器L实例评测|云原生】自定制轻量化表单Docker快速部署云耀云服务器

🤵‍♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…...

无涯教程-JavaScript - ACOTH函数

描述 ACOTH函数返回数字的反双曲余切。 语法 ACOTH (number)争论 Argument描述Required/OptionalNumberThe absolute value of Number must be greater than 1. i.e., Number must be must be less than -1 or greater than 1.Required Notes 用于计算双曲反余切的方程为-…...

Qt QTreeWidge解决setItemWidget后,导致复选框失效

一、问题: QTreeWidget某一项加上itemWidget后,导致复选框失效问题 二、解决方法 将要加上的widget控件加到该项的后续的列,即控件跟复选框不同一列 三、具体代码 QTreeWidget* treeW new QTreeWidget; treeW->setColumnCount(2); /…...

strncpy

strncpy: 函数介绍: 函数原型: char *strncpy(char *dest, const char *src, int n) 返回值:dest字符串起始地址 说明: 1、当src字符串长度小于n时,则拷贝完字符串后,剩余部分将用空字节填…...

c++学习【23】matlab实现FOC算法

% 创建Figure窗口和滑块 figure;Id_slider uicontrol(Style, slider, Position, [100 50 120 20], ...Min, -5, Max, 5, Value, 1.5, Callback, updateVoltage); Id_text uicontrol(Style, text, Position, [100 80 120 20], String, d轴电流: 1.5);Iq_slider uicontrol(Sty…...

2020-2023中国高等级自动驾驶产业发展趋势研究-概念界定

1.1 概念界定 自动驾驶发展过程中,中国出现了诸多专注于研发L3级以上自动驾驶的公司,其在业界地位也越来越重要。本报告围绕“高等级自动驾驶” 展开,并聚焦于该技术2020-2023年在中国市场的变化趋势进行研究。 1.1.1 什么是自动驾驶 自动驾驶…...

ICPC 2022 网络赛 h (模拟

#include<bits/stdc.h> using namespace std; using VI vector<int>; using ll long long; const int mod 20220911;//枚举数位&#xff0c;枚举这一位余数是几 //每一位的限制&#xff0c; //如果有repeat 就下一个 int change(string x){int res 0 ;for(int …...

如何保护您的工业网络?

工业网络通过连接机器、设备和系统&#xff0c;在实现工业流程的高效生产、监控和管理方面发挥着关键作用。保护工业网络&#xff0c;确保其关键资产和流程的完整性、可用性和机密性&#xff0c;是工业组织的首要任务。在本文中&#xff0c;我们将探讨保护工业网络安全面临的障…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...