多线程基础 保姆级讲解

多线程基础

    • 认识线程
      • 1)线程是什么
      • 2) 为啥要有线程
      • 3) 进程和线程的区别 (经典面试题)
    • 多线程
      • 线程的创建方式
        • 方法1 继承 Thread 类
        • 方法2 实现 Runnable 接口
        • 方法3 使用匿名内部类创建 Thread 子类对象
        • 方法4 匿名内部类创建 Runnable 子类对象
        • 方法5 lambda 表达式创建 Thread 子类对象
    • Thread类及常见方法
    • Thread 的常见构造方法
    • Thread 的几个常见属性
      • getId()
      • getName()
      • getState()
      • isDeamon()
      • isAlive()
      • isInterrupted()

认识线程

1)线程是什么

一个线程就是一个 “执行流”. 每个线程之间都可以按照顺序执行自己的代码. 多个线程之间 “同时” 执行着多份代码.

2) 为啥要有线程

A.首先, “并发编程” 成为 “刚需”. 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU.
而并发编程能更充分利用多核 CPU 资源.

B.有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做一些其他的工作, 也需要用到并发编程.

C.其次, 虽然多进程也能实现 并发编程, 但是线程比进程更轻量.
创建一个进程,消耗的时间比较多 消耗在资源分配上,进程是资源分配的基本单位 分配内存是一个大活 操作系统内部有一个数据结构,把空闲的内存分块整理好。当我们进行申请内存空间的时候,操作系统就会从这样的数据结构中,找到一个合适大小的空闲内存返回给对应的进程
虽然这里的数据结构可以一定程度上提高效率,单整体来说,管理的空间比较多,相比之下还是一个耗时的操作
销毁一个进程,消耗的时间比较多
调度一个进程,消耗的时间比较多 相比之下
创建线程比创建进程更快.
销毁线程比销毁进程更快.
调度线程比调度进程更快.

最后, 线程虽然比进程轻量, 但是人们还不满足, 于是又有了 “线程池”(ThreadPool) 和 “协程”(Coroutine)
(关于线程池我们后面再介绍. 关于协程的话题我们此处暂时不做过多讨论. )

线程不能独立存在,而是要依附于进程。 一个进程可以包含一个或者多个线程。
一个进程最开始的时候,至少有一个线程。这个线程负责完成执行代码的工作。也可以根据需要创建出更多的线程,从而使当前实现 并发编程的效果

并发编程
并行和并发统称为并发 并行:多个线程同时在多个CPU上执行 并发:进程太多,CPU核心数太少。就需要多个进程在同一个CPU核心上轮番执行。只要**轮转的速度足够快,**看起来就是这些进程在
*同时执行

总结:进程包含线程 =》一个线程对应一个CPB =》 一个进程包含一个或者多个线程 =》 每个线程都有自己的状态,上下文,优先级,记账信息 =》 每个线程都可以独立的去CPU上调度执行 =》 同一个进程的CPB共用了同样的内存指针和文件描述符表 =》创建线程(PCB)不需要重新申请资源 =》线程创建和销毁的效率都更高

3) 进程和线程的区别 (经典面试题)

1.进程是包含线程的. 每个进程至少有一个线程存在,即主线程。
2.进程和进程之间不共享资源. 同一个进程的线程之间共享同一个资源(内存资源和硬盘资源),
3.进程是系统分配资源的最小单位,线程是系统调度的最小单位。
4.进程和线程都是用来 实现并发编程 场景的,但是线程比进程更轻量,更高效
5.进程和进程具有独立性,一个进程挂了,不会影响其他进程。但是同一个进程的线程之间,是可能相互影响的(线程安全问题和线程出现异常,后续会详细介绍)

多线程

线程的创建方式

方法1 继承 Thread 类
  1. 继承 Thread 来创建一个线程类.
  2. 创建 MyThread 类的实例
  3. 调用 start 方法启动线程
package thread;class MyThread01 extends Thread{@Overridepublic void run() {while (true){System.out.println("Mythrend01");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}public class Demo923 {public static void main(String[] args) {
MyThread01 t = new MyThread01();
t.start();}
}
方法2 实现 Runnable 接口
  1. 实现 Runnable 接口
  2. 创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数.
  3. 调用 start 方法
package thread;class MyRunnable01 implements Runnable{@Overridepublic void run() {System.out.println("MyRunnable01");}
}public class Demo923 {public static void main(String[] args) {
MyRunnable01 myRunnable01 = new MyRunnable01();
Thread t2 = new Thread(myRunnable01);
t2.start();}
}

提示: Runnable是表示一个 可运行的任务,这个任务是交给线程执行还是交给其他实体执行,Runnable本身并不关心
Runnable的写法和直接继承Threa之间的区别,是解耦合 run()和start()方法的区别 run()方法描述了要执行什么样的任务 而 start()方法,则是调用系统API,在操作系统内创建出线程。

方法3 使用匿名内部类创建 Thread 子类对象
package thread;public class Demo923 {public static void main(String[] args) {Thread t1 = new Thread(){@Overridepublic void run() {System.out.println("使用匿名类创建 Thread 子类对象");}
};
t1.start();}
}
方法4 匿名内部类创建 Runnable 子类对象
package thread;
public class Demo923 {public static void main(String[] args) {
Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("使用匿名类创建 Runnable 子类对象");}
};
Thread t1 = new Thread(r1);
t1.start();}
}
方法5 lambda 表达式创建 Thread 子类对象
package thread;
public class Demo923 {public static void main(String[] args) {Thread t1 = new Thread(() -> {System.out.println("使用匿名类创建 Thread 子类对象");});t1.start();}
}

(还有一些创建线程的方式后面会详细介绍哦)

Thread类及常见方法

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关
联。
每个执行流,也需要有一个对象来描述,类似下图所示,(如同每个人都要有身份证标识身份)而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。
thread对象

Thread 的常见构造方法

Thread() 创建线程对象 Thread(Runnable target) 使用 Runnable 对象创建线程对象

Thread(String name) 建线程对象,并命名

Thread(Runnable target, String name) 使用Runnable 对象创建线程对象,并命名

【了解】Thread(ThreadGroup group,Runnable target) 线程可以被用来分组管理,分好的组即为线程组,这
个目前我们了解即可

Thread 的几个常见属性

hread 的几个常见属性

getId()

ID是线程的唯一标识,不同线程不会重复。(这里的id是java给你这个线程分配的,不是系统API提供的线程,更不是PBC的id)

getName()

创建线程的时候可以去指定name不影响线程的执行,只是给线程起个名字,后续在调试的时候,比较方便区分
名称是各种调试工具用到的 比如:使用jconsole(JDK中自带的工具)来观察进程里的多线程情况 jconsole.exe在JDK安装目录的bin目录里面

jconsole
jconsole

getState()

getState() 获取线程的状态,状态表示线程当前所处的一个情况,下面我们会进一步说明

isDeamon()

isDeamon() 判断线程是否为守护线程
守护线程(后台线程)相比之下,后台线程,不结束,不影响整个进程的结束。
默认情况下,一个线程是前台线程
如果前台线程,没有执行结束,此时整个进程是不会结束的

举个例子

public class Demo923 {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.setDaemon(true);t.start();}
}

在这里插入图片描述

虽然主线程飞快执行完了,但是 t 这个前台线程没执行完,所以进程不结束

package thread;
public class Demo923 {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.setDaemon(true);t.start();}
}

在这里插入图片描述

此时把t改为后台线程之后,主线程飞快执行完了,此时也没有其他前台进程了,于是进程就结束了。t来不及执行就结束了。

isAlive()

isAlive()判定内核线程是不是已经没了

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());}

在这里插入图片描述

ture线程开始这两个日志谁先打印不一定,线程是并发执行的,并发调度的顺序不确定,取决于系统的调度器(如果大家尝试,大概率先打印true,因为调用start之后,新的线程被创建也是有一定开销的,创建过程中,主线程就执行了println语句。当然也无法排除极端情况,主线程正好卡了一下,是新线程的println语句先打印)

isInterrupted()

isInterrupt()判断一个线程是否被终止

`如何中断一个线程 如何让一个线程停止运行 在java中,要终止/销毁一个线程,做法比较唯一,就是想办法让run()方法尽快执行结束

可以在代码中手动设置标志位,来作为run()的执行结束的条件

public class Demo923 {private static boolean isQuit = false;public static void main(String[] args) {Thread t = new Thread(()->{while (!isQuit){System.out.println("线程工作中");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}
}

当前的这个代码,是使用一个isQuit变量作为标志位,可以通过修改isQuit的值让run()尽快结束。

上述方法不够优雅:

1.需要手动创建变量
2.当线程内部在sleep的时候,主线程修改变量,新线程不能及时响应 因此就需要使用另外的方式来完成上述线程中断操作

(今天先讲到这里,中断方法下一篇做详细解释哦~~)

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

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

相关文章

塑封芯片多大才需要点胶加固保护?

塑封芯片多大才需要点胶加固保护? 塑封芯片是否需要点胶加固保护,并不完全取决于芯片的大小,而是由多种因素共同决定的。以下是一些影响是否需要点胶加固保护的主要因素: 芯片的应用场景:如果芯片所处的环境较为恶劣&a…

买量内卷严重,小游戏们不得不迈向长期展线

小游戏这两年有多火爆自然不必多说。根据《2024 年 1-6 月中国游戏产业报告》,今年 1-6 月国内移动游戏市场实销收入 1075.17 亿元,同比增长 0.76%,较为平稳;但同时小程序移动游戏(即小游戏)收入达 166.03 …

如何在网站建设中不被外包建站公司忽悠?

让我来公开一些代建站行业忽悠甲方背后的套路吧, 长篇干货警告! 像我们这一行网站建设的外包服务商,忽悠人的情况是普遍的事情! 很多低劣的外包公司,凭着做一单忽悠一单的手段,成为了我们建站行业的害群之…

Python 使用selenium 4.25 进行爬虫(1)

都说python做爬虫比较好,于是我跟着大家的脚步学习python进行爬虫,但是调试了半天,出现各种各样的问题,最终都得到实现了,下面我们来看具体的代码: from selenium import webdriver from selenium.webdriv…

秋招突击——9/13——携程提前准备和实际面经——专程飞过去线下,结果一面挂(难受)

文章目录 引言面经收集面经整理一1. ArrayList和LinkedList2. 线程安全的列表和链表有么?如果没有怎么实现?3. threadlocal4. synchronized锁升级过程及原理5. ReentrantLock原理,以及和synchronized的对比6. 线程池工作原理7. redis常用数据…

Blob数据类型报错时如何获取错误信息

const pdfOrg async (record) > {// 假设 transferExportPdf是结构 result 返回的错误信息let result await transferExportPdf({ batchId: record.batchId });//blob 结构const blob new Blob([result], {type: result.type,});if (blob.type "application/json&q…

【源码+文档+调试讲解】重庆旅游景点数据分析系统python

摘 要 重庆旅游景点数据分析系统是一个专门为旅游管理部门和景点运营商设计的信息化工具,它通过集成和分析各种数据来优化景点管理和提升游客体验。该系统能够实时收集游客流量、景点信息、满意度反馈等关键信息,帮助管理者洞察游客行为和市场趋势。系统…

MySQL 中 FIELD() 自定义排序示例详解,实现按照指定顺序排序

在 MySQL 中,你可以使用 ORDER BY FIELD() 来自定义排序顺序。这个函数允许你指定字段的自定义排序顺序 field() 函数:是将查询的结果集按照指定顺序排序 格式: FIELD(str,str1,str2,str3,…) 什么时候用: 想让某几个特定的字段…

Java_Se 数组与数据的存储

数组是相同类型数据的有序集合。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。 数组的四个基本特点: 1.长度是确定的。数组一旦被创建,它的大小就是不可以改变的。 2.其元素…

【JavaSE】-- 类和对象(2)

文章目录 6. 封装6.1 封装的概念6.2 访问限定符6.3 封装拓展之包6.3.1 包的概念6.3.2 导入包中的类6.3.3 自定义包 7. static成员7.1 再谈学生类7.2 static修饰成员变量7.3 static修饰成员方法7.4 static成员变量初始化 8. 代码块8.1 代码块概念以及分类8.2 普通代码块8.3 构造…

关于优化活动页面的大尺寸图片的展示问题

背景 在处理一个对清晰度要求较高的页面时,由于可渲染的图片达到了3840 * 10k的分辨率,所以前端这边在接收到活动页面的图片会相当大(2MB起步的),然后就会出现一个图片缓慢从上到下渲染的过程动画,对于C端…

为电机一体化应用提供一种双通道集成电机驱动方案的电机驱动芯片-SS6811H

电机驱动芯片 - SS6811H为舞台灯光和其它电机一体化应用提供一种双通道集成电机驱动方案。SS6811H是一款双通道H桥驱动芯片;用PWM接口进行控制;具有两个独立的H桥驱动通道,每个H桥可提供较大输出电流1.6A (在24V和Ta 25C适当散热条件下)&…

【转型必看】Java到AI,程序员的逆袭秘籍!

随着技术的不断进步,人工智能(AI)已经成为当今科技领域最热门的话题之一。许多开发者开始考虑从传统的软件开发领域,如Java,转向人工智能领域,今天小编和大家一起来探讨Java开发者是否可以转型到人工智能&a…

神经网络(五):U2Net图像分割网络

文章目录 一、网络结构1.1第一种block结构1.2第二种block结构1.3特征图融合模块1.4损失函数1.5总体网络架构1.6代码汇总1.7普通残差块与RSU对比 二、代码复现 参考论文:U2-Net: Going deeper with nested U-structure for salient object detection   这篇文章基于…

网站建设完成后,国家为什么要求域名备案后才能上线

网站建设完成后,域名备案后才能上线的原因有很多。以下是对这些原因的详细分析: 维护国家互联网安全:备案制度有助于防范网络恐怖分子利用国内网站发布恐怖言论和宣传恐怖活动,从而保护国家的互联网安全。保护用户合法权益&#…

虚拟实训室建设需要投入哪些设备?实际效果如何?

随着虚拟现实技术的飞速发展,虚拟现实实训室作为现代教学的重要组成部分,正逐步成为提升教学质量和学生实践能力的重要手段。本文将从虚拟现实实训室建设所需的软硬件设备投入以及实际效果两个方面进行探讨。 软、硬件设备投入 硬件设备方面,…

Linux高级IO之五种IO模型

文章目录 Linux高级IO之五种IO模型IO的理解阻塞式IO非阻塞IO信号驱动式IOIO多路转接异步IO同步和异步 Linux高级IO之五种IO模型 IO的理解 IO模型其实更像是网络部分的延伸和拓展,在学习完计算机网络之后,结合Linux系统,我们就该认识到&…

[数据库实验三]安全性

目录 一、实验目的与要求: 二、实验内容: 三、实验小结 一、实验目的与要求: 1、设计用户子模式 2、根据实际需要创建用户角色及用户,并授权 3、针对不同级别的用户定义不同的视图,以保证系统的安全性 二、实验内…

SAP ABAP ‘‘ 和 `` 的区别

DATA(LV_01) 100. DATA(LV_02) 200.’ ’ 输出为 Char 输出为 String 如下直接定义赋值就会报错 DATA ls_value TYPE TABLE OF string. *ls_value VALUE #( ( A ) ). "报错行 ls_value VALUE #( ( A ) ).使用的场景:动态SQL取数 DATA OPTION TYPE STRI…

生成速度更快!AI绘画工具新版 SD WebUI Forge 保姆级安装教程,更低的显存更快的生成速度!

大家好,我是程序员晓晓 不知道平时经常使用 SD WebUI 的小伙伴发现没有,随着安装插件和模型越来越多,WebUI 时不时会出现卡顿或爆显存的情况,尤其在低显存的硬件上更加明显,只能不停的重启来解决。 估计是 WebUI 的作…