【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来观察该进程内的多线程情况~
这里我们主要介绍jconsole,jconsole是jdk自带的程序
而jconsole我们可以在jdk包里找到
-
首先我们要先找到
jdk的安装地址

-
在地址处找到
jdk然后打开bin目录,然后再列表中找到jconsole.exe
这里我们要注意的是:
- 在启动
jconsole.exe之前,我们得确保IDEA的程序已经跑起来了




sleep
上述的线程,我觉得他在while循环中转的太快了,想要他慢点~
那我们就可以使用Thread.sleep();,sleep是Thread的静态方法

需要注意的是:我们使用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岁孩子完成不来任务
那么这个任务就是和你这个线程有一定耦合关系的~
而我们创建一个线程,需要进行两个关键操作:
-
明确线程要执行的任务
任务本身,不一定和线程 概念 强相关的
- 这个任务只是单纯的执行一段代码,这个任务是使用单个线程执行还是多个线程执行,亦或是别的方式(信号处理函数/协程/线程池)都没什么区别~
- 任务本身,就可以将任务本身提取出来,此时就可随时把代码改成使用其他方式来执行这个任务~
-
调用系统的
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几个常见属性
| 属性 | 获取方法 |
|---|---|
| ID | getId() |
| 名称 | 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;//枚举数位,枚举这一位余数是几 //每一位的限制, //如果有repeat 就下一个 int change(string x){int res 0 ;for(int …...
如何保护您的工业网络?
工业网络通过连接机器、设备和系统,在实现工业流程的高效生产、监控和管理方面发挥着关键作用。保护工业网络,确保其关键资产和流程的完整性、可用性和机密性,是工业组织的首要任务。在本文中,我们将探讨保护工业网络安全面临的障…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...
工厂方法模式和抽象工厂方法模式的battle
1.案例直接上手 在这个案例里面,我们会实现这个普通的工厂方法,并且对比这个普通工厂方法和我们直接创建对象的差别在哪里,为什么需要一个工厂: 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类: 两个发…...
SFTrack:面向警务无人机的自适应多目标跟踪算法——突破小尺度高速运动目标的追踪瓶颈
【导读】 本文针对无人机(UAV)视频中目标尺寸小、运动快导致的多目标跟踪难题,提出一种更简单高效的方法。核心创新在于从低置信度检测启动跟踪(贴合无人机场景特性),并改进传统外观匹配算法以关联此类检测…...
Linux 进程管理学习指南:架构、计划与关键问题全解
Linux 进程管理学习指南:架构、计划与关键问题全解 本文面向初学者,旨在帮助你从架构视角理解 Linux 进程管理子系统,构建系统化学习路径,并通过结构化笔记方法与典型问题总结,夯实基础、明确方向,逐步掌握…...
1.springmvc基础入门(一)
1.Spring MVC概念 Spring MVC 是 Spring Framework 提供的 Web 组件,全称是 Spring Web MVC,是⽬前主流的实现 MVC 设计模式的框架,提供前端路由映射、视图解析等功能。 Java Web 开发者必须要掌握的技术框架。 2.Spring MVC 功能 MVC&am…...
