java_ 多线程知识笔记(一)

news2025/2/26 23:00:12

文章目录

  • 前言:
  • 1.如何理解线程
  • 2.进程和线程的关系
  • 3.多线程编程
    • 第一种:继承Thread类
    • 第二种:实现Runnable 接口:
    • 第三种:使用Lambda表达式
  • 4.Thread 用法
    • 1.Thread常见的构造方法
    • 2.Thread的几个常见的属性
  • 5.等待一个线程
  • 6.并发和并行

前言:

为什么要引入多线程编程

java引用进程的概念主要为了解决 “并发编程” 的问题,即多个程序一起运行;
锁紧弄成编程已经可以解决并发编程的问题,并且可以利用CPU多核资源了
在这里插入图片描述

因此,线程也就应运而生,线程也叫 “轻量级进程”;
解决并发编程问题,最终是为了让创建,销毁,调度的速度更快;

1.如何理解线程

为什么线程更轻?
因为线程把创建资源,释放资源的过程都给省下了

如何理解线程
看例子:
上篇博客我们把纺织厂的例子来比喻进程,这篇博客继续使用这个例子:
在这里插入图片描述
为什么说线程把创建资源,释放资源的过程都给省下了呢?
因为 线程A和线程B共享进程里面的资源,就相当于本来是1个人吃10只鸡,多加了一个线程之后就相当于多加了一个人,现在就相当于2个人吃10只鸡;一个进程里面的所有线程都是资源都是共享的,因此创建线程不需要创建和释放资源

2.进程和线程的关系

  1. 进程和线程的关系是进程包含线程,一个进程最少有一个线程,也可以有多个线程;但是进程里面的线程应该视具体资源而定,不能一味增加,否则会造成程序崩溃
  2. 同一个进程里多个线程之间,共用了进程的同一份资源(内存文件描述符表)
    注意:在同一个进程中,线程1 new的对象,线程2,3都可以直接使用,
    线程1 打开的文件在线程2,3里都可以直接使用
  3. 操作系统实际调度时,是以线程为基本单位调度的,上篇文章说操作系统是以进程为基本单位调度,是一个进程里面只有一个线程的前提下;如果每个进程都有多个线程,每个线程都是独立在CPU上调度的,每个线程也都有自己的执行逻辑 (执行流);
  4. 一个核心执行的是一个线程,如果一个进程有两个线程,那么线程A可能在 核心1上执行,线程B可能在核心2上执行,实际调度过程中,不关心进程,只关心线程;
  5. 一个线程也是通过PCB来描述的,一个进程里面可能对应一个PCB,也可能对应多个PCB,上篇博客里介绍的PCB状态,上下文,优先级,记账信息等都是每个线程所特有的,但是一个进程里的pid,内存指针和文件描述符表都是相同的

画图解释一下多进程和多线程的关系
在这里插入图片描述
第一种方式是多进程,会浪费调大量资源,花费大量成本,去重新申请一个进程
第二种是多线程方式,直接在一个进程里完成即可,省下很多成本,并且提高了速度

重点:是不是一味的在一个进程里面申请线程,速度就可以一直提升呢?
答案肯定是不行的,增加线程数量的时候,也不是一直可以提高速度的,因为纺织厂的空间是有限的,生产线过多,机会拥挤,反而会影响速度;同理,线程太多,核心数目有限,大量的时间反而浪费在线程调度上了

3.多线程编程

java中操作多线程,最核心的类是Thread,记住就行了;不要纠结为啥是这个类
创建线程的目的是为了成立一个独立的执行流(执行一段代码)

第一种:继承Thread类

看代码:

class MyThread extends Thread{
    //重写子类的 run()方法,告诉线程要做什么工作
    @Override
    public void run() {
        while(true){
            System.out.println("==MyThread==");
            //休眠1s,让线程运行速度变慢,方便观看效果
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}


public class Test1 {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();//真正创建了一个线程
        
        //理解为死循环打印==main==即可
        while(true){
            System.out.println("==main==");
            thread.sleep(1000);//休眠1s,让线程运行速度变慢,方便观看效果
        }
    }
}

在这里插入图片描述
问题:为什么不在main()中调用run方法?
如果在main()调用run,此时就没有创建新线程,全程都只有main线程在运行

在这里插入图片描述
在这里插入图片描述
以上就是多线程编程的一个典型例子,即main线程和thread线程同时执行,谁先谁后我们也不确定;


  1. 操作系统调度线程的时候,是==“抢占式执行”==,具体哪个线程在先,哪个线程在后,取决于操作系统调度器,实现具体策略
  2. new Thread对象,并不是创建线程(这里说的线程是 系统内核里的 PCB),调用start才是创建PCB才是货真价实的线程
  3. PCB对应的是线程,一个进程最少有一个PCB,也可以有多个PCB,同一个进程的pid是相同的,不同进程的pid是不同的
  4. PCB是一个数据结构,体现的是进程/线程是如何实现,如何被描述出来的

java中创建线程的写法有很多种,上面写的是第一种即继承Thread,重写run方法

第二种:实现Runnable 接口:

class MyRunnable implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("==MyRunnable==");
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

public class Test1 {

    public static void main(String[] args) throws InterruptedException {

        Runnable runnable = new MyRunnable();//创建一个任务
        Thread thread = new Thread(runnable);//把任务交给线程来处理
        thread.start();//真正创建了一个线程,去执行任务
        
       //理解为死循环打印==main==即可
        while(true){
            System.out.println("==main==");
            sleep(1000);//休眠1s,让线程运行速度变慢,方便观看效果
        }

    }
}

结果:打印如果依旧是 顺序不确定的
在这里插入图片描述

为什么要这样写? 目的是为了让线程和线程之间要做的工作分开.解耦合;

第三种:使用Lambda表达式

这一种方法是最推荐的,也是最方便的

public static void main(String[] args) {
//直接把Lambda任务传给Thread构造方法
        Thread thread = new Thread(() ->{
            System.out.println("==Lambda==");
        });
        thread.start();
        System.out.println("==main==");
    }

4.Thread 用法

1.Thread常见的构造方法

在这里插入图片描述

    //构造方法举例
		Thread t1 = new Thread();
        Thread t2 = new Thread(new MyRunnable());
        Thread t3 = new Thread("名字");
        Thread t4 = new Thread(new MyRunnable(), "名字");

2.Thread的几个常见的属性

在这里插入图片描述

  1. 获取id和名字
 public static void main(String[] args) {
        Thread thread1 = new Thread("第一个线程的名字");
        System.out.println(thread1.getName());//获取线程的名字
        System.out.println(thread1.getId());//获取线程的id
    }

结果:
在这里插入图片描述


2.获取线程状态
getState()方法;

public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println("==thread1==");
        });
        thread1.setDaemon(true);
        thread1.start();//线程运行
        System.out.println(thread1.getState());//在线程正在运行是获取线程状态,就是runnable
        thread1.join();//等到线程结束
        System.out.println(thread1.getState());//线程结束之后,再获取线程状态就是结束的状态了,TERMINATED
    }

运行结果:
在这里插入图片描述


  1. 看看线程状态是否存活
    isAlive()方法:是判断当前系统里面的 线程 是不是真的存在,并不是判断对象是否真的存在
    在这里插入图片描述

在这里插入图片描述

 public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println("==thread1==");
        });
      
        System.out.println(thread1.isAlive());//false,并没有创建线程,只是创建了对象,所以是false
        thread1.start();
        System.out.println(thread1.isAlive());//true,创建了线程,并且并没有执行完,所以是true
      
        thread1.join();
       
        System.out.println(thread1.isAlive());//false,线程已经执行完任务并且线程已经销毁,所以线程状态是false

    }
如果thread的run还没跑,isAlive()就是false; 如果thread的run正在跑,isAlive()就是true; 如果thread的run跑完了,isAlive()就是false;
  1. 线程中断
    这里的线程中断不是说让正在运行的线程立即终止,而是通知线程你应该停止了,是否真的停止,取决于线程具体的写法
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

5.等待一个线程

线程调度是一个随机的过程,等待线程就是了控制两个线程结束的顺序
在这里插入图片描述

6.并发和并行

在这里我们讨论的都是线程,并不是进程
在这里插入图片描述

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

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

相关文章

【好书推荐】计算机网络:自顶向下方法(第七版)

人生的美妙之处在于迷上一样东西。人生苦短,少做些虚无缥缈的事。 – 刘慈欣-《三体》 推荐理由 自计算机网络诞生以来,经过数十年的发展,计算机的体系已经非常庞大,同时计算机网络也大大促进了人类社会的发展。无数大佬前赴后继…

【python量化】将Informer用于股价预测

写在前面Informer模型来自发表于AAAI21的一篇best paper《Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting》。Informer模型针对Transformer存在的一系列问题,如二次时间复杂度、高内存使用率以及Encoder-Decoder的结构限制&…

后台管理不可忽视,华为云会议最新支持管理员分权分域

如今,跨地域, 跨组织,需要随时随地接入的远程沟通协作变得愈加频繁,众多企业开始纷纷建设符合自身需求的智能会议室。在会议系统的众多能力中,后台管理,这项常常被C端用户忽略的能力,B端的企业却…

真的够可以的,基于Netty实现了RPC框架

RPC全称Remote Procedure Call,即远程过程调用,对于调用者无感知这是一个远程调用功能。目前流行的开源RPC 框架有阿里的Dubbo、Google 的 gRPC、Twitter 的Finagle 等。本次RPC框架的设计主要参考的是阿里的Dubbo,这里Netty 基本上是作为架构…

1. Spring Boot 3 入门学习教程之开发第一个 Spring Boot 应用程序

Spring Boot 3 入门学习教程之开发第一个 Spring Boot 应用程序0. 前言1. Spring Boot 介绍2. 系统要求2.1 Servlet容器2.2 GraalVM Native Image(GraalVM 原生镜像)3. 安装Spring Boot 开发环境3.1 安装JDK3.2 安装Spring Boot构建工具3.2.1 方式一&…

C++标准库分析总结(九)——<仿函数/函数对象>

目录 1.functor仿函数简介 2 仿函数的分类 3 仿函数使用 4 仿函数可适配的条件 1.functor仿函数简介 仿函数是STL中最简单的部分,存在的本质就是为STL算法部分服务的,一般不单独使用。仿函数(functors)又称为函数对象&…

【InnoDB Cluster】修改已有集群实例名称及成员实例选项

【InnoDB Cluster】修改已有集群实例名称,成员实例名称和选项 文章目录【InnoDB Cluster】修改已有集群实例名称,成员实例名称和选项修改名称修改已有集群实例名称修改已有集群实例的成员实例名称修改成员服务器操作系统的主机名直接修改元数据库中的表使…

力扣(LeetCode)88. 合并两个有序数组(C++)

朴素思想 朴素思想&#xff0c;开第三个数组&#xff0c;对 nums1nums1nums1 和 nums2nums2nums2 进行二路归并。 class Solution { public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {vector<int> nums3(mn);int i 0,j …

2.2 Linux启动初始化文件系统

为了方便了解和调试我们的Linux系统,我们需要将proc,debugfs,tmp等挂载起来,否则我们我发了解系统的进程,负载等信息,如下是未进行任何挂载时,我们无法通过ps等方法查看系统任何进程信息: 一,挂载proc fs proc是一个伪文件系统,(伪文件系统只存在内存中,而不占用存…

Node.js 入门教程 2 Node.js 简史

Node.js 入门教程 Node.js官方入门教程 Node.js中文网 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录Node.js 入门教程2 Node.js 简史2.1 一点历史2.2 20092.3 20102.4 20112.5 20122.6 20132.7 20142.8 20152.9 20162.10 20172.11 20182.12 2…

聊一聊微服务常见配置中心工作原理

0. 环境 nacos版本&#xff1a;1.4.1 Spring Cloud : 2020.0.2 Spring Boot &#xff1a;2.4.4 Spring Cloud alibaba: 2.2.5.RELEASE Spring Cloud openFeign 2.2.2.RELEASE 测试代码&#xff1a;github.com/hsfxuebao/s… 1. 配置中心基础 1.1 为什么要用配置中心&…

Js逆向教程-15滑块流程 极验

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; Js逆向教程-15滑块流程 极验 一、滑块是什么&#xff1f; 区分是否是机器人。根据滑动轨迹区分是否是人操作的。 滑块肯定有滑动条 …

亚马逊云科技持续创新、领势而行,re:Invent颠覆想象

当一行行代码成为托起数字社会的基础架构&#xff0c;社会发展开始面临真正意义上的变革与重塑。作为云计算领域的探路者与引领者&#xff0c;亚马逊云科技持续创新、领势而行&#xff0c;正不断塑造并颠覆着大众关于云计算未来的想象。 2006年 开端 2006年&#xff0c;亚马逊…

【单片机基础】I2C通信-基于STC89C52RC

文章目录1、IIC总线结构2、IIC总线传输协议3、完成工程代码1、IIC总线结构 IIC总线是philips公司在八十年代初推出的一种串行、半双工总线。主要用于近距离、低速的芯片之间通信&#xff1b;IIC总线有两根双向的信号线&#xff0c;一根数据线SDA用于收发数据一根时钟线SCL用于…

Mac 使用paralles 从零搭建hadoop集群

目录 1. 虚机的安装与配置 1.1 安装parallels 1.2 安装fedora系统 1.3 fedora的配置 1.3.1 内存和硬盘配置 1.3.2 网络配置 1.3.3 共享文件夹 1.4 虚拟机克隆 与 加载 2. 免密登录 2.1 分别查看master&#xff0c; slave01&#xff0c;slave02 的ip 2.2 查看各虚机的…

关于mpy电压采集模块的那些事儿(ads1256 ads8688 ad7606)

先来个人生碎碎念&#xff0c;越狱第三次失败了&#xff0c;而且第四次也可能失败&#xff0c;没错就是这么尴尬&#xff0c;绝对越狱的事件还有917天&#xff0c;其实比较麻木了&#xff0c;越狱成功与否都无所谓了&#xff0c;其实现在出去&#xff0c;外头的疫情&#xff0c…

【学生网页设计作业源码】基于HTML+CSS+JavaScript简单的大学生书店(13个页面) 二手书店电子商务网站模板源码

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

常见的数据结构基本介绍

文章目录常见的数据结构介绍栈和队列的介绍数组数据结构链表数据结构二叉树和二叉查找树平衡二叉树红黑树结构常见的数据结构介绍 数据结构是计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。 通常情况下&#xff0c;精心选择的数据结构可以带来更…

应用ceph文件系统存储(ceph-13.2.10)

记录&#xff1a;333 场景&#xff1a;在CentOS 7.9操作系统上&#xff0c;部署ceph-13.2.10集群。应用ceph文件系统(ceph file system)&#xff1b;主要是创建ceph文件系统、客户端挂载ceph文件系统等操作。 版本&#xff1a; 操作系统&#xff1a;CentOS 7.9 ceph版本&am…

JS获取音频的总时长,解决audio.duration 为 NaN || Infinity 问题

目录一、需求分析二、发现问题1.使用浏览器内置播放器<audio>无法显示时长2.获取总时长为 NaN || Infinity三、疑惑点四、解决方案一、需求分析 后端的接口中包含音频链接&#xff0c;前端需要自定义一个播放器播放音频。 二、发现问题 1.使用浏览器内置播放器<audi…