线程与多线程编程

1. 线程 

1.1 概念

线程又可以称为轻量级进程 ,在进程的基础上做出了改进。

一个进程在刚刚启动时,做的第一件事就是申请内存和资源,进程需要把依赖的代码和数据,从磁盘加载到内存中这件事是比较耗费时间的,有的业务场景可能会频繁的创建,销毁进程,也就导致了大量的开销。而线程则省去了分配资源和释放资源带来的开销。

1.2 线程与进程的区别 

与进程相同,线程也可以用PCB描述,所拥有的属性也是大致相同的。不同点在于,每个线程都有自己独立的系统资源,而多个线程的系统资源是可以相互共享的。所以这些线程之间需要的重复的系统同资源就只需要申请一次避免了重复的开销

 举个例子:1线程需要资源A,B  2线程需要资源B,C  3线程需要资源 A,C。现在1线程执行了,2线程执行时就只需要申请资源 C, 再到3线程执行时则不需要再申请资源了。

也不是所有线程都可以共享资源,系统会把能资源共享的线程分成组,就称为线程组,而线程组也是进程的一部分,也就是一个进程是由多个线程组成的 

 注意:

  1. 进程是包含线程的
  2. 每个线程也是一个独立的执行流,可以执行一些代码并单独参与到cpu的调度中(状态,上下文,优先级,记账信息,每个线程都有自己的一份
  3. 每个进程有自己的资源,进程中的线程共用这一份资源(内存空间和文件描述符表)
  4. 进程是资源分配的基本单位,线程是调度执行的基本单位
  5. 同一个进程中的线程之间,可能会互相干扰引起线程安全问题
  6. 进程和进程之间不会互相影响,如果同一个进程中的线程,抛出异常,可能会影响到其他线程,把整个进程中的所有线程都终止

 2. 多线程编程

写代码的时候,可以使用多进程进行并发编程,也可以使用多线程并发编程。

在Java中是不太推荐多进程编程的,

2.1 创建线程的方法

2.1.1 继承 Thread  

1.  创建Thread子类 重写run方法

class MyThread extends Thread {@Overridepublic void run() {System.out.println("调用了MyThread类中的run方法");}
}

 run方法是该线程的入口,不需要手动调用,jvm会在线程创建好时自动调用

2. 创建子类的实例

Thread t = new MyThread();

3. 调用 Thread类中的start方法

 t.start();

注意:

  • 调用Thread类中的start方法,才会真正调用系统api在内核中创建出线程,直接调用run方法是不会创建出线程的
  • 一个Thread对象只能调用一次start方法

上面我们说了,每个线程都是一个独立的执行流,就相当于,我们创建的线程中的run方法和main方法是同时执行的

例如以下代码:

class MyThread2 extends Thread {@Overridepublic void run() {while(true) {System.out.println("MyThread中的run方法");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class ThreadDemo2 {public static void main(String[] args) throws InterruptedException {Thread t = new MyThread2();t.start();while(true) {System.out.println("main方法");Thread.sleep(1000);}}
}

输出结果:

如果把

t.start();

改为

t.run();

 则不会打印 “main方法” 因为 t并没有创建出线程 ,run方法是在main方法的线程中执行

2.1.2 实现 Runnable接口 

实现Runnable 接口重写 run方法

class MyThread3 implements Runnable {@Overridepublic void run() {System.out.println("MyThread3中的run方法");}
}

 创建一个 MyThread3 对象作为参数传入 Thread的构造方法然后调用start

  public static void main(String[] args) {Thread t = new Thread(new MyThread3());t.start();}
2.1.3 使用匿名内部类
public class ThreadDemo4 {public static void main(String[] args) {Thread t = new Thread() {@Overridepublic void run() {System.out.println("MyThread4中的run方法");}};t.start();}
}
public class ThreadDemo5 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("MyThread5中的run方法");}});t.start();}
}
2.1.4 使用lambda表达式
public class ThreadDemo6 {public static void main(String[] args) {Thread t = new Thread(()-> {System.out.println("MyThread6中的run方法");} );t.start();}
}

 推荐使用这种写法。

2.2 Thread类的属性和方法

2.2.1 构造方法
  1. Thread() 无参构造方法,创建一个新的线程对象。
  2. Thread(Runnable target)  使用指定的Runnable对象作为线程的目标,创建一个新的线程对象。
  3. Thread(String name) 使用指定的名称创建一个新的线程对象。
  4. Thread(Runnable target, String name) 使用指定的Runnable对象和名称创建一个新的线程对象。
  5. Thread(ThreadGroup group, Runnable target) 使用指定的线程组和Runnable对象创建一个新的线程对象。
  6. Thread(ThreadGroup group, Runnable target, String name) 使用指定的线程组、Runnable对象和名称创建一个新的线程对象。

 解释:每个线程都有一个名称,如果没有给它命名则会默认为Thread-0,Thread-1......累加。当一个线程运行时我们可以通过jdk的工具 jconsole 查看线程的状态,名称等。这个工具在jdk目录底下的bin文件夹中

示例代码:

public class ThreadDemo7 {public static void main(String[] args) {Thread t = new Thread(() -> {while(true) {System.out.println("ThreadDemo7");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}, "ThreadDemo7");t.start();}
}

运行该代码然后打开jconsole

如图所示:

我们在本地进程即可看到我们运行的ThreadDemo7,点击连接即可查看线程的状态等信息

线程的名字是可以重复的

2.2.2 常见的属性

解释: 

  1. id:每个线程都有一个唯一的id,用于标识线程。

  2. 名称:线程可以设置一个可选的名称来标识自己。可以通过setName(String name)方法设置线程的名称。

  3. 状态:线程在运行过程中会处于不同的状态。(下面会详细讲解)

  4. 优先级:每个线程都有一个优先级,用于指示线程在竞争CPU资源时的相对重要性。优先级范围从1到10,默认为5。可以通过setPriority(int priority)方法设置线程的优先级。

  5. 是否后台进程:线程可以设置为后台进程。后台进程不会阻止程序的终止,当所有前台线程结束时,后台线程也会自动结束。可以通过setDaemon(boolean on)方法将线程设置为后台进程

  6. 是否存活:线程是否仍然存活(即尚未终止)。

  7. 是否被中断:线程可以通过调用interrupt()方法中断自己或其他线程 以及通过interrupted()静态方法检查当前线程是否被中断,并清除中断状态。

  线程中断注意事项:

示例代码:

public class ThreadDemo8 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {//currentThread() 方法是获取当前线程的实例,即这里的twhile(!Thread.currentThread().isInterrupted()) {System.out.println("ThreadDemo8");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("执行完毕");});t.start();Thread.sleep(5000);System.out.println("让线程结束");t.interrupt();}
}

当我们运行代码结果如下:

我们可以看到,代码并不像我们预期的那样结束,而是在继续运行 ,这是因为 sleep的原因,因为,当我们运行interrupt()时,sleep()可能还未结束,于是sleep就被提前唤醒了

sleep被提前唤醒会做两件事:

1. 抛出InterruptedException异常

2.将Thread对象的isInterrupted标志位设置为false

所以运行完interrupt()后标志位已经被设为true但是sleep又把它改回false了,所以会继续执行。我们要结局这个问题只需在catch中加一个break

2.2.3 join方法

如果我们希望某个线程在另一个线程之前执行完,可以用到join方法

示例代码:

public class ThreadDemo10 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for(int i = 0; i < 5; i++) {System.out.println("ThreadDemo10");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();t.join();//让main线程等待t线程执行完System.out.println("希望t线程执行完再执行这条语句");}
}

 运行结果:

执行join后,如果t线程在运行中,main线程就会阻塞(主动放弃去cpu上执行 )直到t运行结束

除了无参数的join方法还有带参数的join方法

 解释:

  • join():死等,一定会等到调用该方法的线程执行完
  • join(long millis):带超时时间的等待,如果在设定的时间内,调用该方法的线程没有执行完,则不会继续等待
  • join(long millis, int nanos):带超时时间的等待,精确到纳秒,如果在设定的时间内,调用该方法的线程没有执行完,则不会继续等待

示例代码: 

public class ThreadDemo11 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for(int i = 0; i < 5; i++) {System.out.println("ThreadDemo11");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();//让join只等2秒,如果没等到就不等了t.join(2000);System.out.println("main");}
}

运行结果:

 interrupt() 方法可以把阻塞 等待的join提前唤醒

 

 2.3 线程的状态

Java中有以下线程状态:

  1. NEW:线程被创建但还未开始执行。
  2. RUNNABLE:线程正在执行或准备开始执行。(就绪状态)
  3. BLOCKED:锁竞争引起的阻塞。(线程安全会详讲)
  4. WAITING:线程正在等待另一个线程的特定操作完成。(不带时间的死等,join()或wait()会进入这个状态
  5. TIMED_WAITING:线程正在等待另一个线程的特定操作完成,但设置了最大等待时间。(使用sleep()方法或者带超时时间的join()方法会进入这个状态)
  6. TERMINATED:线程已经执行完毕结束。

示例代码:

public class ThreadDemo12 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for(int i = 0; i < 5; i++) {System.out.println("ThreadDemo12");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//线程被创建但还没开始执行System.out.println(t.getState());t.start();//线程在执行中System.out.println(t.getState());t.join();//线程执行完毕System.out.println(t.getState());}
}

 执行结果:

 

我们也可以通过 jdk的jconsole工具查看线程的状态 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

matlab simulink 永磁同步电机PI调速控制

1、内容简介 略 27-可以交流、咨询、答疑 2、内容说明 永磁同步电机调速控制 永磁同步电机PI调速控制 永磁同步电机PI调速控制、PMSM 3、仿真分析 略 4、参考论文 略 链接&#xff1a;https://pan.baidu.com/s/1AAJ_SlHseYpa5HAwMJlk1w 提取码&#xff1a;rvol 路…

科研者的福利!一个集论文、代码、数据集为一体的网站

Papers with Code 是一个总结了机器学习论文及其代码实现的网站。大多数论文都是有GitHub代码的。这个网站最好的地方就是对机器学习做了任务分类&#xff0c;检索对应的模型非常方便。早在18年Paper With Code创立时就轰动一时&#xff0c;仅创立一年就被Facebook收购。 Pape…

Spring AOP记录接口访问日志

Spring AOP记录接口访问日志 介绍应用范围组成通知&#xff08;Advice&#xff09;连接点&#xff08;JoinPoint&#xff09;切点&#xff08;Pointcut&#xff09;切面&#xff08;Aspect&#xff09;引入&#xff08;Introduction&#xff09;织入&#xff08;Weaving&#x…

Linux--初识和基本的指令(3)

目录 1.前言 1.指令 1.1 cat指令 1.2 echo指令 1.3 more 指令 1.4 less指令 1.5 什么时候使用less和more 1.6 head指令 1.7 tail指令 1.8 wc指令 1.9 与时间相关的指令 1.9.1 date指令 1.9.2 cal指令 1.10 16.find指令&#xff1a;&#xff08;灰常重要&#x…

千梦网创:熟悉抖音内容创作的切入方式

因为身边抖音网红的资源比较近&#xff0c;所以虽然一直没有露脸去做短视频运营&#xff0c;但是最近也是跟随朋友一起开始了短视频的学习之路。 在参观过一些“超级直播间”之后&#xff0c;我们敲定了未来的两个盈利方向&#xff0c;这两个方向可以将我们身边的资源极致利用…

MyBatis-逆向工程

1.简单生成 1.添加依赖和插件 <dependencies><!-- MyBatis核心依赖包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.9</version></dependency><!-- MySQL驱动…

金蝶Apusic应用服务器deployApp接口任意文件上传漏洞复现 [附POC]

文章目录 金蝶Apusic应用服务器deployApp接口任意文件上传漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 金蝶Apusic应用服务器deployApp接口任意文件上传漏洞复现 [附POC] 0x01 前言 免责声明…

【前端】-【electron】

文章目录 介绍electron工作流程环境搭建 electron生命周期&#xff08;app的生命周期&#xff09;窗口尺寸窗口标题自定义窗口的实现阻止窗口关闭父子及模态窗口自定义菜单 介绍 electron技术架构&#xff1a;chromium、node.js、native.apis electron工作流程 桌面应用就是…

常见的攻击防护

只做模拟机器使用&#xff0c;不使用真实机器 目录 一、 DHCP饿死和防护应对措施.................................. 1 1&#xff0c; 实验拓扑&#xff1a;...................................................... 2 2&#xff0c; 实验配置............................…

Web自动化测试怎么做?Web自动化测试的详细流程和步骤

1.什么是web自动化测试 自动化&#xff08;Automation&#xff09;是指机器设备、系统或过程&#xff08;生产、管理过程&#xff09;在没有人或较少人的直接参与下&#xff0c;按照人的要求&#xff0c;经过自动检测、信息处理、分析判断、操纵控制&#xff0c;实现预期的目标…

opencv阈值处理

阈值处理 二值化 自适应阈值 OTSU二值化

latex表格中内容过多如何换行【已解决】

最近在写论文的时候放了一个表格&#xff0c;但是表格看起来特别大&#xff0c;因为想让某些内容多的单元格完成换行操作 首先在main.tex引入makecell包 \usepackage{makecell} 然后回到表格找到你想换行的单元格&#xff0c;把\makecell{}加进去&#xff0c;然后在需要换行的…

基于物联网技术的基站能耗监控解决方案-安科瑞 蒋静

摘 要&#xff1a;随着社会的不断发展和进步&#xff0c;人们对通信基站的需求增加。随着通信基站大规模的建设和使用&#xff0c;基站内部的电源情况、供电安全保障或节能减排等问题&#xff0c;仍然是基站建设的着重问题。不管是建设者还是使用者&#xff0c;都应当注重用电安…

[socket 弹 shell] msg_box3

前言 题目比较简单&#xff0c;没开 Canary 和 NX. Arch: amd64-64-littleRELRO: Full RELROStack: Canary foundNX: NX disabledPIE: PIE enabledRWX: Has RWX segments 漏洞利用与分析&#xff1a; 白给的函数调用&#xff0c;其中 ptr 10 是用…

Long-Context下LLM模型架构全面介绍

深度学习自然语言处理 原创作者&#xff1a;cola 随着ChatGPT的快速发展&#xff0c;基于Transformer的大型语言模型(LLM)为人工通用智能(AGI)铺平了一条革命性的道路&#xff0c;并已应用于知识库、人机界面和动态代理等不同领域。然而&#xff0c;存在一个普遍的限制:当前许多…

模拟业务流程+构造各种测试数据,一文带你测试效率提升80%

我们做软件测试的时候&#xff0c;经常需要页面有点数据&#xff0c;特别是涉及到一些数据统计的测试用例的时候&#xff0c;更是需要源源不断的测试数据让前端页面生成对应的报表测试统计的数据正确性。 如果我们通过手工的方式操作业务流程来实现数据的构造的话&#xff0c;少…

【Cisco Packet Tracer】子网划分的计算及实验

子网划分&#xff1a;Internet组织机构定义了五种IP地址&#xff0c;有A、B、C三类地址。A类网络有126个&#xff0c;每个A类网络可能有16777214台主机&#xff0c;它们处于同一广播域。而在同一广播域中有这么多节点是不可能的&#xff0c;网络会因为广播通信而饱和&#xff0…

在 ArcGIS 软件中添加左斜宋体(东体)的方法与步骤

河流水系在作图时一般设置为左斜宋体&#xff08;东体&#xff09;、蓝色&#xff0c;比如黄河、青海湖等&#xff0c;如下图所示&#xff1a; 标准地图水系注记 下面讲解如何在 ArcGIS 软件中添加左斜宋体&#xff08;东体&#xff09;&#xff0c;首先需要下载左斜宋体&#…

【开源】基于JAVA语言的校园疫情防控管理系统

项目编号&#xff1a; S 037 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S037&#xff0c;文末获取源码。} 项目编号&#xff1a;S037&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生2.2 老师2.3 学校管理部门 三、…

《管家婆》辉煌2005+(V4.0)简单教程

《管家婆》辉煌2005&#xff08;V4.0&#xff09;简单教程 呉師傅 运行环境&#xff1a;   操作系统推荐使用Win2000&#xff08;32位&#xff09;、WinXP&#xff08;32位&#xff09;、Win7&#xff08;位&#xff09; 兼容&#xff1a;Win7&#xff08;64位&#xff09…