JavaEE-多线程上

news2024/11/8 21:50:32

文章目录

  • 线程概述
    • 进程/线程
    • 多线程的作用
    • JVM关于线程资源的规范
    • 关于Java程序的运行原理
  • 并发与并行
    • 并发(concurrency)
    • 并行(parallellism)
    • 并发编程与并行编程
  • 线程的调度策略
    • 分时调度模型
    • 抢占式调度模型
  • 创建线程
    • 线程类分析入门
    • 实现线程的第一种方式
    • 实现线程的第二种方式
  • 线程的生命周期
    • 线程的生命周期概述
    • 线程生命周期间的关系(含UML图)

线程概述

进程/线程

  • 进程是指操作系统中的一段程序, 它是一个正在执行的程序实例, 具有独立的内存空间和系统资源, 所以进程之间资源不共享, 如文件, 网络端口等, 在计算机运行时, 一般是先创建进程, 后创建线程, 一个进程通常可以包含多个线程
  • 线程是指的是进程中的一个执行单元, 是进程的一部分, 负责在进程中执行代码, 每一个线程都有自己的栈和程序计数器, 并且可以共享进程的资源, 多个线程可以在同一个时刻执行不同的操作, 从而提高程序的执行效率, 线程与线程之间的资源并不是完全共享的, 下面会详细介绍…

大白话总结:

  • 一个应用程序就是一个进程
  • 一个进程里面有多个线程执行任务

多线程的作用

最重要的就是提高处理问题的效率, 能够使CPU在处理一个任务时同时处理多个线程, 这样可以充分利用CPU的资源, 提高CPU的资源利用率

JVM关于线程资源的规范

我们用下面的一张图来说明
在这里插入图片描述
在同一个进程的多个线程之间, Heap(堆), Method Area(方法区)资源是共享的, Java Virtual Machine Stack(Java虚拟机栈), Native Method Stack(本地方法栈), The pc Register(程序计数器)这些都是不能够共享的

所以就存在线程安全的问题
比如对于变量来说, 局部变量存在Java虚拟机栈, 所以不存在线程安全问题, 但是实例变量, 静态变量都存在于堆中, 就会存在线程安全的问题

关于Java程序的运行原理

  • 当JVM启动的时候, JVM会自动开启一个主线程(main-thread), 然后去调用main方法
    所以main方法都是在主线程中执行的
  • 除了主线程之外, 还会启动一个垃圾回收线程(GC), 因此启动JVM, 至少启动了两个线程
  • 除上述线程之外, 程序员可以手动创建其他的线程并启动

并发与并行

早期的人们使用的单核的CPU, 那是不是不能同时运行多个程序呢? 答案是否定的, 下面的关于并发与并行就可以解释这个问题

并发(concurrency)

  • 在使用单核心CPU时候, 微观层面一个时间点只能执行一个指令, 但多个指令被快速的轮换执行,使得在宏观上具有多个指令同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干端,使多个指令快速交替的执行

下面的这张图就可以很好的说明这个问题
在这里插入图片描述
横轴对应的是时间, 纵轴对应的是ABC三个程序, 围观层面, 某一时间点只能执行一个程序, 但是通过CPU高速的在ABC三个程序中进行调度切换, 让我们宏观上看起来是三个程序同时执行的, 这种情况就是并发

并行(parallellism)

  • 这种情况针对的就是多核心CPU的情况, 此时在一个时间点, 微观层面上也可以通过多个核心同时多个程序来达到真正意义上的"同时执行"
    在这里插入图片描述

并发编程与并行编程

  • 多核心CPU资源紧缺(或者是单核心CPU)的前提下, 如果开启了多个线程, 但是只有一个CPU核心可以提供资源, 那么这些线程就会抢夺CPU的时间片, 竞争执行机会, 这就是通过 并发 的方式实现多线程
  • 多核心CPU资源比较充足的情况下, 此时有多个CPU核心可以来提供资源, 此时一个进程中的线程就会被分配到多个CPU核心上同时执行, 这就是通过 并行 的方式实现多线程
  • 不管并发还是并行,都提高了程序对CPU资源的利用率,最大限度地利用CPU资源,而我们使用多线程的目的就是为了提高CPU资源的利用率

那么Java实现多线程的方式是并发还是并行呢?

  • 至于Java多线程实现的是并发还是并行?上面所说,所写多线程可能被分配到一个CPU内核中执行,也可能被分配到不同CPU执行,分配过程是操作系统所为,不可人为控制。所以,如果有人问我我所写的多线程是并发还是并行的?我会说,都有可能

线程的调度策略

存在线程调度的原因是因为, 当多个线程被分配到同一个CPU核心执行的时候, 此时这些程序就会抢夺CPU的时间片从而或者执行权, 所以就存在执行的先后问题

分时调度模型

  • 所有线程轮流使用CPU的执行权, 并且平均每个线程的占用时间, 也就是绝对平均

抢占式调度模型

  • 让优先级高的线程以较大的概率优先获得CPU的执行权, 如果线程的优先级相同, 那么就会随机选择一个线程获得CPU的执行权, 而Java采用的就是抢占式调度模型

创建线程

线程类分析入门

这个是JDK17帮助文档的链接
JDK17帮助文档
通过API文档, 我们可以查询到我们需要的一些信息内容, 从而完成编程(这里不推荐查看中文的帮助文档)


构造方法
在这里插入图片描述
构造方法可以通过传入一个字符串然后指定该线程的名称


static Thread currentThread()
在这里插入图片描述

这是一个静态方法, 通过这个方法可以获取到当前线程的Thread信息, 其实有点类似于之前学的this


void setName(String name)

在这里插入图片描述
这是一个实例方法, 通过一个线程的引用调用之后可以设置当前线程的名称(其实每一个线程都有一个默认的名称)


String getName()

在这里插入图片描述
这是一个实例方法, 作用就是调用之后可以获得当前线程的名称


实现线程的第一种方式

执行逻辑如下

  • 创建一个类继承Thread(java.lang)包下的, 默认导入)类
  • 重写Thread中的run()方法(这个run()相当于每个线程的main函数)
  • 创建这个类的对象, 然后调用start()方法, 开启线程

我们给一个代码的案例测试一下

package thread_demo.thread_demo01;

public class Thread01 {
    public static void main(String[] args) {
        // 当执行main函数的时候, 系统自动的就开启了两个线程
        Thread t = new MyThread();
        t.start();

        // 主线程的内容
        for(int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + "---->" + i);
        }
    }
}

/**
 * 创建线程的第一种方式是创建一个类继承Thread(所以这个类其实也就是一个线程)
 * 1. 创建一个类继承Thread这个线程类(所以此时这就是一个线程)
 * 2. 重写run方法(这就相当于每一个线程运行的入口)
 * 3. new一个线程对象然后调用start()方法启动一个线程
 */
class MyThread extends Thread {
    @Override
    public void run() {
        for(int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + "---->" + i);
        }
    }
}

执行结果如下
在这里插入图片描述
两个线程会无规则的交替执行
初学者好多不理解这个代码的执行逻辑, 首先我们在main中创建了一个线程对象, start()的作用就是开启一个线程, 然后就弹栈了, 此时JVM中就存在了两个线程同时执行(不含GC), 所有就会出现交替执行的情况

实现线程的第二种方式

执行逻辑如下

  • 创建一个类实现Runnable接口
  • 重写其中的run()方法
  • 创建这个类的对象(匿名的也可以), start()开启一个线程

给一个代码案例测试一下

package thread_demo.thread_demo02;

public class Thread02 {
    public static void main(String[] args) {
        // 直接new一个对象调用创建一个t线程
        Runnable r = new MyThread();
        Thread t = new Thread(r, "test1");
        // 开启t线程
        t.start();

        // 利用匿名内部类的方式创建一个线程对象
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + "--->" + i);
                }
            }
        }, "test2");
        // 开启t1线程
        t1.start();

        // 直接就不接收变量直接开启一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + "--->" + i);
                }
            }
        }, "test3").start();

        // 最后在操作一下主线程
        Thread mainThread = Thread.currentThread();
        mainThread.setName("main");
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "--->" + i);
        }
    }
}

/**
 * 创建线程的第二种方式是定义一个类去实现Runnable接口, 我们推荐使用这种方式开启多线程
 * 1. 定义一个类实现Runnable接口
 * 2. 重写run方法
 * 3. Thread t = new Thread(传入这个类的对象)
 * 4. t.start() 去开启一个线程
 */
class MyThread implements Runnable{
    @Override
    public void run() {
        for(int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + "--->" + i);
        }
    }
}

执行结果也是多个线程交替执行, 原理和第一种是一致的
在这里插入图片描述

线程的生命周期

线程的生命周期概述

线程的生命周期主要就是指的一个线程在不同时期的状态情况, 大致可以分

  • 6种(JDK层面)
  • 7种(我们平时常说的)

首先我们从JDK层面分析一下为什么是6种
我们查看一下帮助文档找到Thread.State这个枚举类型
在这里插入图片描述
在这里插入图片描述

  • NEW : 新建状态, 也就是执行start()之前的状态
  • RUNNABLE : 可运行状态, 这个状态分为两个子状态
    就绪状态 和 运行状态
  • WAITING : 等待状态, 不限时间(比如等待用户输入)
  • TIMED_WAITING : 超时等待状态, 限制时间(比如Thread.sleep(毫秒)
  • BLOCKED : 阻塞状态, 比如遇到了一些关于锁的操作
  • TERMINATED : 时亡状态, run()方法结束

线程生命周期间的关系(含UML图)

下面我们尝试绘制一个UML来描述一下各个状态之间的关系
在这里插入图片描述
图上说明的十分的详细了…, 我们再阐述一下

  • 首先线程处于一个NEW的新建状态, 然后通过start()创建一个线程, 此时线程处于RUNNABLE(就绪状态)
  • 位于RUNNABLE(就绪状态)的线程拥有抢夺CPU时间片的能力, 当抢夺到了CPU时间片之后, 线程的run()方法就开始执行, 此时线程处于RUNNABLE(运行状态), 当抢夺到的CPU时间片用完了之后, 线程会再次进入到RUNNABLE(就绪状态), 下次执行时会接着上一次的执行, 这个过程中靠的是CPU的调度机制
  • 当程序在RUNNABLE(运行状态)遇到Thread.sleep(毫秒)类似的间隔的时候, 会进入到TIMED_WAITING超时等待状态, 此时会返还先前抢到的CPU时间片, 所有的等待休眠期度过之后, 会进入到RUNNABLE(就绪状态)等待下一次抢夺CPU时间片
  • 当程序在RUNNABLE(运行状态)遇到例如接收到需要等待用户输入的指令的时候, 就会进入到WAITING等待状态, 这个等待状态是没有时间的限制的(比如接收到输入为止)
  • run()方法彻底执行结束之后, 就会触发到TERMINATED状态…

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

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

相关文章

论文阅读:三星-TinyClick

《Single-Turn Agent for Empowering GUI Automation》 赋能GUI自动化的单轮代理 摘要 我们介绍了一个用于图形用户界面&#xff08;GUI&#xff09;交互任务的单轮代理&#xff0c;使用了视觉语言模型Florence-2-Base。该代理的主要任务是识别与用户指令相对应的UI元素的屏幕…

Tomcat servlet response关于中文乱码的经验

前言 最近修改老项目项目&#xff0c;使用zuul网关返回的中文内容乱码了&#xff0c;如果使用GBK或者GB2312编码确正常显示&#xff0c;稍微实验了一下&#xff0c;发现里面很多细节&#xff0c;毕竟Springboot对我们做了很多事情&#xff0c;而且当我们使用不同的模式会出现很…

服务器的免密登录和文件传输

在天文学研究中&#xff0c;通常会采用ssh登录服务器&#xff0c;把复杂的计算交给服务器&#xff0c;但是如果你没有进行额外的配置&#xff0c;那么登录服务器&#xff0c;以及和服务器进行文件传输&#xff0c;每次都要输入账号和密码&#xff0c;比较不方便&#xff0c;Win…

Windows Server NTFS磁盘变RAM的处理过程

问题描述 客户服务器的磁盘数据爆满&#xff0c;需要将磁盘进行扩容&#xff0c;因为是虚拟机所以先在虚拟化平台上将原来的磁盘空间改大&#xff0c;再进入系统&#xff0c;在磁盘管理器上将需要扩容的磁盘进行扩展。扩展完后系统报文件系统有问题&#xff0c;扩容的磁盘容量…

No.23 笔记 | WEB安全 - 任意文件漏洞 part 5

本文全面且深入地探讨了文件上传漏洞相关知识。从基础概念出发&#xff0c;清晰地阐述了文件上传漏洞的定义及其产生的本质原因&#xff0c;同时列出了该漏洞成立的必要条件。详细说明了文件上传漏洞可能对服务器控制权、网站安全以及业务运营带来的严重危害。 文中还深入解析了…

[mysql]子查询的概述和分类及单行子查询

子查询引入 查询的基本结构已经给大家了,子查询里面也是有一些新的内容,子查询其实就是在查询中嵌套另一个查询,叫嵌套查询可能大家更容易理解一点..,类似与FOR循环和FOR循环的嵌套,这一章是我们查询的最难的部分,大家 难度是查询的顶峰,多表查询和子查询是非常重要,SQL优化里…

EDA --软件开发之路

之前一直在一家做数据处理的公司&#xff0c;从事c开发&#xff0c;公司业务稳定&#xff0c;项目有忙有闲&#xff0c;时而看下c&#xff0c;数据库&#xff0c;linux相关书籍&#xff0c;后面跳槽到了家eda公司&#xff0c;开始了一段eda开发之路。 eda 是 electric design …

【移动应用开发】使用多媒体--通知/播放音频/视频

目录 一、具体步骤 二、运行截图 1. 开启通知权限 2. 播放音乐 3. 播放视频 三、源代码 1. activity_main.xml 2. activity_video_player.xml 3. activity_notification.xml 4. 一些配置 5. MainActivity 6. VideoPlayerActivity 7. NotificationActivity 8. And…

代码备份管理 —— Git实用操作

目 录 Git那些事版本控制系统git环境搭建运行bashbash命令行git账号全局设置本地仓库的存在远程仓库的存在git管理基本流程git仓库的文件夹常用git命令工作区变为git仓库add命令使用branch命令使用checkout命令使用commit命令使用仓库状态查询代码变更后提交删除或恢复文件管理…

windows下安装及使用labelme

1.进入Anaconda Prompt对话窗口 输入&#xff1a;conda create --namelabelme python3.6 # 创建一个叫labelme的环境 conda create --namelabelme python3.6 2.激活新建的环境&#xff0c;进入 输入&#xff1a;activate labelme #激活环境 activate labelme 3.安装pyqt5 …

集群渲染是一台节点输出吗?它是云渲染农场吗

集群渲染并非单一节点的输出&#xff0c;而是一种分布式计算技术&#xff0c;它通过多台计算机协同工作来加速3D渲染过程。这种技术常被视作云渲染农场的前身&#xff0c;两者在提高渲染效率方面有着相似之处。接下来&#xff0c;让我们深入了解集群渲染与云渲染农场之间的联系…

建筑行业内部知识库的重要性与实施策略

在当今瞬息万变的建筑行业中&#xff0c;企业面临着前所未有的竞争挑战。为了在市场中保持竞争力&#xff0c;建筑企业不仅需要拥有先进的技术和设备&#xff0c;还必须具备高效的知识管理能力。内部知识库&#xff0c;作为知识管理的核心工具&#xff0c;正逐渐成为建筑企业提…

【Fastjson反序列化漏洞:深入了解与防范】

一、Fastjson反序列化漏洞概述 Fastjson是一款高性能的Java语言JSON处理库&#xff0c;广泛应用于Web开发、数据交换等领域。然而&#xff0c;由于fastjson在解析JSON数据时存在安全漏洞&#xff0c;攻击者可以利用该漏洞执行任意代码&#xff0c;导致严重的安全威胁。 二、F…

数据结构 —— AVL树

目录 1. AVL的概念 2.AVL树的结构 3.AVL树的插入 3.1 平衡因子更新 4. 旋转 4.1 旋转的原则 4.2 右单旋 4.2.1 右单旋代码实现 4.3 左单旋 4.3.1 左单旋代码实现 4.4 左右双旋 4.4.1 左右双旋代码实现 4.5 右左双旋 ​编辑 4.5.1 右左双旋代码实现 5. AVL树的判断…

[GXYCTF 2019]Ping Ping Ping 题解(多种解题方式)

知识点: 命令执行 linux空格绕过 反引号绕过 变量绕过 base64编码绕过 打开页面提示 "听说php可以执行系统函数&#xff1f;我来康康" 然后输入框内提示输入 bjut.edu.cn 输入之后回显信息,是ping 这个网址的信息 输入127.0.0.1 因为提示是命令…

Python小游戏16——开心消消乐

运行结果显示 代码如下 import pygame import random # 初始化pygame pygame. init() # 定义一些常量 WIDTH 600 HEIGHT 600 NUM_GRID8 GRID_SIZE WIDTH // NUM_GRID FPS 30 # 定义颜色 WHITE (255&#xff0c; 255&#xff0c;255) BLACK(0&#xff0c;0&#xff0c;0) COL…

基于树莓派的安保巡逻机器人--(一、快速人脸录入与精准人脸识别)

目录 零、前言 一、人脸检测 二、人脸识别 1、采集人脸 2、训练人脸识别模型 3、人脸识别应用 零、前言 随着智能安防需求的增长&#xff0c;基于人工智能和物联网的安保系统逐渐成为趋势。树莓派因其低成本、高扩展性等特点&#xff0c;成为很多AI项目的理想平台。本文将为大…

HTB:BoardLight[WriteUP]

目录 连接至HTB服务器并启动靶机 1.How many TCP ports are listening on BoardLight? 2.What is the domain name used by the box? 3.What is the name of the application running on a virtual host of board.htb? 4.What version of Dolibarr is running on Board…

react18中redux-saga实战系统登录功能及阻塞与非阻塞的性能优化

redux-saga中的effect常用的几个是有区分出阻塞与非阻塞的&#xff0c;这里主要看下call和fork两者的区别。 实现效果 非阻塞的task执行&#xff0c;不用等到登录成功后请求的list接口完成&#xff0c;点击退出按钮可以立即退出 阻塞task的执行&#xff0c;必须等到登录成功…

【JavaEE】【多线程】进阶知识

目录 一、常见的锁策略1.1 悲观锁 vs 乐观锁1.2 重量级锁 vs 轻量级锁1.3 挂起等待锁 vs 自旋锁1.4 普通互斥锁 vs 读写锁1.5 可重入锁 vs 不可重入锁1.6 不公平锁 vs 公平锁 二、synchronized特性2.1 synchronized的锁策略2.2 synchronized加锁过程2.3 其它优化措施 三、CAS3.…