JavaEE 【知识改变命运】02 多线程(1)

news2024/11/24 17:29:49

文章目录

  • 线程是什么?
    • 1.1概念
      • 1.1.1 线程是什么?
      • 1.1.2 为什么要有线程
      • 1.1.3 进程和线程的区别
      • 1.1.4 思考:执行一个任务,是不是创建的线程或者越多是不是越好?(比如吃包子比赛)
      • 1.1.5 ) Java 的线程 和 操作系统线程 的关系
    • 1.2 对多线程程序的理解
      • 1.2.1 ) Java 的线程 和 操作系统线程 的关系
    • 1.3 创建线程的两种方式
      • 1.3.1 继承 Thread 类
      • 1.3.2实现Runnable接口
      • 1.3.3两者创建方法的对比
      • 1.3.4 其他形式创建
        • 1.3.4.1 匿名类创建Thread子类对象
        • 1.3.4.2匿名内部类创建 Runnable ⼦类对象
        • 1.3.4.2 lambda 表达式创建 Runnable ⼦类对象
    • 1.4 jconsloe使用

线程是什么?

1.1概念

1.1.1 线程是什么?

  1. 线程是就是一个执行流,每个执行流之间都可以按照一定顺子执行自己的代码,多个线程可以”同时“执行多分代码
  2. 举例:进程就像一个程序,比如qq,迅雷,进程是程序的一次执行过程,或者是正在运行的一个程序,是动态的过程有它自己的产生存在和消亡的过程
  3. 线程是又进程创建的,是进程的一个实体,一个进程可以拥有多个线程,把迅雷比作一个进程,而同时下载多条视频,就是多条线程在工作。

1.1.2 为什么要有线程

  1. “并发式编成”已经成为了编成界的“刚需”
  2. 单核 CPU 的发展遇到了瓶颈. 要想提⾼算⼒, 就需要多核 CPU. ⽽并发编程能更充分利⽤多核 CPU资源.
  3. 有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做⼀些其他的⼯作, 也需要⽤到并发编程.
  4. 重点:进程虽然可以进程并发编成,但是线程比进程更轻量。

解释:进程的创建也需要申请资源,而申请资源对于系统的性能影响比较大。
在这里插入图片描述
举个例子:张三要开一个工厂,工业园相当于是操作系统,地皮是固定的,张三的工厂就像一个进程,生产线就像一个线程,张三的工厂是生产皮包的,里面只有一条生产线,现在我们要提高产量,是重新建一个场比较好?,还是在原来的工厂中加一条生产线好呢?,肯定是只增加一条生产线,这样就节省了工业园地皮的面积资源,也利用张三工厂的面积资源,线程的出现更好的利用了系统的资源。
在这里插入图片描述

  1. 其次, 虽然多进程也能实现 并发编程, 但是线程⽐进程更轻量,

创建线程比创建进程更快
销毁线程比销毁进程更快
调度线程比调度进程更快。

  1. 线程虽然比进程更轻量,但是⼈们还不满⾜, 于是⼜有了 “线程池”(ThreadPool) 和 “协程”(Coroutine)

1.1.3 进程和线程的区别

1.进程里面包含线程:每一个进程里面至少包含一个主线程
2.进程是申请资源的最小单位
3.线程是cpu调度的最小单位
4.进程和进程之间不共享内存空间. 同⼀个进程的线程之间共享同⼀个内存空间 ,所以进程与进程之间互不影响,线程与线程之间可能产生影响
5.一个线程受到影响,会导致进程的结束,⼀个进程挂了⼀般不会影响到其他进程. 但6.是⼀个线程挂了, 可能把同进程内的其他线程⼀起带⾛(整个进程崩溃).
在这里插入图片描述

1.1.4 思考:执行一个任务,是不是创建的线程或者越多是不是越好?(比如吃包子比赛)

我们先思考下创造进程的方式:
在这里插入图片描述
虽然双进程比单进程确实提升了效率,但是消耗资源太大了,太浪费资源了
我们思考创建线程的方法
在这里插入图片描述
效率确实提高了,比进程消耗的资源小

我们再思考一下,根据上面的情况,我们无限创建线程,是不是线程创建的越多越好呢?
在这里插入图片描述
答案肯定不是的,这样会出现线程争抢资源问题,如果一个线程崩溃就会造成整个进程的崩溃

其实我们可以根据cpu的逻辑处理器来创建线程
在这里插入图片描述

当线程小于逻辑处理器,创建线程会提升效率
当线程大于逻辑处理器,创建线程的线程都是阻塞等待状态,从而没有发挥出线程的效果,创建线程本来就会消耗资源,从而白白消耗资源

  • 总结:通过提升线程,我们可以提高效率,但是要根据实际情况来创建,不能盲目创建

1.1.5 ) Java 的线程 和 操作系统线程 的关系

线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对⽤⼾层提供了⼀些 API 供⽤⼾使⽤(例如 Linux 的 pthread 库).Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进⾏了进⼀步的抽象和封装.

1.2 对多线程程序的理解

1.2.1 ) Java 的线程 和 操作系统线程 的关系

  1. 线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对⽤⼾层提供了⼀些 API 供⽤⼾使⽤(例如 Linux 的 pthread 库).Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进⾏了进⼀步的抽象和封装.
  2. 线程与普通程序的区别:每个线程都是⼀个独⽴的执⾏流,多个线程之间是 “并发” 执⾏的

import java.util.Random; public class ThreadDemo {
    private static class MyThread extends Thread {
        @Override
        public void run() {
            Random random = new Random();
            while (true) {
                // 打印线程名称
                System.out.println(Thread.currentThread().getName());
                try {
                    // 随机停⽌运⾏ 0-9 秒
                    Thread.sleep(random.nextInt(10));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
        Random random = new Random();
        while (true) {
            // 打印线程名称
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(random.nextInt(10));
            } catch (InterruptedException e) {
                // 随机停⽌运⾏ 0-9 秒
                e.printStackTrace();
            }
        }
    } }

在这里插入图片描述

我们可以jconsole这个工具查看线程
在这里插入图片描述
里面有一个mian主线程,和Thread-0子线程

1.3 创建线程的两种方式

1.3.1 继承 Thread 类

    @Override
    //自定义的线程的执行体,线程执行的代码写在这里
    public void run(){
        while (true){
            System.out.println("hello myThread ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    } } class Main{
    public static void main(String[] args) {
        MyThread myThread=new MyThread();//创建一个线程对象
        myThread.start();//启动线程

        while (true){
            System.out.println("hello mainThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

在这里插入图片描述
1:PCB是操作系统层面的
2:Thread是java层面的线程。两者是一 一对应的
3:过程:java创建一个线程------jvm调用系统API--------创建系统中线程------参与调度cpu
在这里插入图片描述
4. 线程执行的顺序是没有规律的,跟cpu的调度有关,因为cpu是“抢占式”执行,所以那个线程当前占用cpu资源是不能确定的
5.能不能调用run()方法执行线程,答案是不行的,因为run方法是java层面的,是不能启动线程的。
6:
在这里插入图片描述

start()开始后,并不意味着线程立马执行,在这里插入图片描述

1.3.2实现Runnable接口

    @Override
    public void run() {
        while (true){
            System.out.println("hello myRunnable");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

} class Main{
    public static void main(String[] args) {
        MyRunnable myRunnable=new MyRunnable();//创建一个线程任务对象
       // 创建 Thread 类实例, 调⽤ Thread 的构造⽅法时将 Runnable 对象作为 target 参数.
        Thread thread=new Thread(myRunnable);//创建一个线程对象,
        thread.start();//启动线程
        while (true){
            System.out.println("hello mainThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    } } ```

这种方法实现底层原码过程:
在这里插入图片描述

其实这种模式是一种及简化的代理模式,这里模拟实现一下

//模拟实现一个Thread类的代理类,模拟Thread的启动
public class ThreadProxy implements Runnable{
    private Runnable target;
    public ThreadProxy(Runnable target) {
        this.target = target;
    }
    @Override
    public void run(){
        if (target!=null){
            target.run();
        }
    }
    public void start(){
        start0();
    }

    private void start0() {
        run();
    }

}
class Main{
    public static void main(String[] args) {
//        ThreadProxy threadProxy01 = new ThreadProxy(new Runnable() {
//            @Override
//            public void run() {
//                while (true){
//                    System.out.println("hello myRunnable");
//                    try {
//                        Thread.sleep(1000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
//        });
//        threadProxy01.start();
        Tiger tiger = new Tiger();
        ThreadProxy threadProxy02 = new ThreadProxy(tiger);

        threadProxy02.start();
    }
}
class animal {
}
class Tiger extends animal implements Runnable{


    public void run(){
        System.out.println("老虎嗷嗷叫");
    }
}

1.3.3两者创建方法的对比

  1. 继承 Thread 类, 直接使⽤ this 就表⽰当前线程对象的引⽤.
  2. 实现 Runnable 接⼝, this 表⽰的是 MyRunnable 的引⽤. 需要使⽤Thread.currentThread()
  3. java是单继承模式,在某种情况下一个类可能已经继承某个父类,这时在用来继承Thread类的方法创造线程是显然不可能的
  4. 实现 Runnable 接⼝,实现了高内聚低耦合的特点,线程和业务逻辑分开,后面修改代码时候,相互影响最小化。
    解释:举例一个场景:两条生成皮鞋的生产线,一条生产皮包生产线
    在这里插入图片描述

1.3.4 其他形式创建

1.3.4.1 匿名类创建Thread子类对象
public class Main {
    public static void main(String[] args) {
        Thread t1=new Thread(){
            @Override
            public void run() {
                while (true){
                    System.out.println("hello myThread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t1.start();
    }
    
}
1.3.4.2匿名内部类创建 Runnable ⼦类对象
public class Main {
    public static void main(String[] args) {
        Thread t2=new Thread(new Runnable(){
            @Override
            public void run() {
                while (true){
                    System.out.println("hello myRunnable");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t2.start();
    }
}

1.3.4.2 lambda 表达式创建 Runnable ⼦类对象
public class Main {
    public static void main(String[] args) {
        Thread t3=new Thread(()->{
            while (true){
                System.out.println("hello myLambda");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t3.start();
   }

}

1.4 jconsloe使用

在这里插入图片描述
我们这里重提一下,先调用的方法会先入栈,后调用的后入栈,后调用的方法执行完后就会出栈。

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

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

相关文章

Linux内核USB2.0驱动框架分析--USB包

一, 包的组成 每个包都由SOP(包起始域)、SYNC(同步域)、Packet Content(包内容)、EOP(包结束域)四部分组成,其中SOP、SYNC、EOP为所有包共有的域&#xff0c…

云轴科技ZStack亮相2024 IDC中国生态峰会,共塑AI时代IT生态新格局

11月21日,2024 IDC中国生态峰会在北京举办,吸引了超过300位生态伙伴齐聚一堂,聚焦行业内最前沿的热点话题。本届峰会以“创见先机,智领风云”为主题,深入探讨宏观经济趋势、技术革新以及如何融合AI与数据技术&#xff…

C0029.在Clion中解决Debug时,提示Process finished with exit code -1的错误

1.错误提示 Process finished with exit code -12.解决办法 如上在使用Debug进行代码调试时,直接出现如上报错,解决办法就是直接点击运行程序,即可查出报错编号,然后根据报错编号来查找问题; 然后在网上就可以根据该…

07-Making a Bar Chart with D3.js and SVG

课程链接 Curran的课程,通过 D3.js 的 scaleLinear, max, scaleBand, axisLeft, axisBottom,根据 .csv 文件生成一个横向柱状图。 【注】如果想造csv数据,可以使用通义千问,关于LinearScale与BandScale不懂的地方也可以在通义千…

读取各种来源格式单细胞数据集构建seurat分析对象,代做生信分析

参考资料和分析注意事项 全流程的分析指导视频 演示数据集网盘文件 分析参数文件路径格式的特别提示 大家给要分析用到的文件路径或目录路径的时候,以D:/omics_tools/demo_data/scrnaseq/GSE189125/GSE189125_5prime_scRNAseq_seqbatchA_counts.txt.gz 这个文件为…

SQL-多表操作

前文所介绍的sql操作都是基于单表进行的,接下来我们来学习多表操作。 多表设计 在实际的项目开发中,会根据业务需求和业务模块之间的关系进行数据库表结构设计,由于业务之间相互关联,所以各个表结构之间也存在着各种联系&#xf…

c++ STL线程安全使用

c STL不是线程安全的&#xff0c;因此在多线程中使用的时候&#xff0c;操作同一个容器&#xff0c;会崩溃&#xff0c;因此需要解决线程安全的问题&#xff1a; 使用实例类似于以下&#xff1a; #include <thread> #include <vector> #include "thread_safe…

Swift 实现判断链表是否存在环:快慢指针法

文章目录 前言摘要描述题解答案题解代码题解代码分析示例测试及结果时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗留问题&#xff0c;最近有时间将以往遗留问题一一完善。 LeetCode - #141 环形链表 不积跬步&#xff0c;无以至千里&#xff1b;不积小流…

SpringCloud实用-OpenFeign 调用三方接口

文章目录 前言正文一、项目环境二、项目结构2.1 包的含义2.2 代理的场景 三、完整代码示例3.1 定义FeignClient3.2 定义拦截器3.3 配置类3.4 okhttp配置3.5 响应体3.5.1 天行基础响应3.5.2 热点新闻响应 3.6 代理类3.6.1 代理工厂3.6.2 代理客户端3.6.3 FeignClient的建造器 四…

C++设计模式行为模式———中介者模式

文章目录 一、引言二、中介者模式三、总结 一、引言 中介者模式是一种行为设计模式&#xff0c; 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互&#xff0c; 迫使它们通过一个中介者对象进行合作。 中介者模式可以减少对象之间混乱无序的依赖关系&…

HarmonyOS:使用ArkWeb构建页面

一、简介 页面加载是Web组件的基本功能。根据页面加载数据来源可以分为三种常用场景&#xff0c;包括加载网络页面、加载本地页面、加载HTML格式的富文本数据。 页面加载过程中&#xff0c;若涉及网络资源获取&#xff0c;需要配置ohos.permission.INTERNET网络访问权限。 二、…

矩阵的拼接

矩阵的拼接分为横向拼接和纵向拼接 注意&#xff1a;横向拼接要求两矩阵行数相同&#xff0c;纵向拼接要求两矩阵列数相同 h o r z c a t horzcat horzcat和 v e r t c a t vertcat vertcat函数 h o r z c a t ( a , b ) horzcat(a,b) horzcat(a,b)将 a a a和 b b b横向拼接&a…

SpringCloud框架学习(第五部分:SpringCloud Alibaba入门和 nacos)

目录 十二、SpringCloud Alibaba入门简介 1. 基本介绍 2.作用 3.版本选型 十三、 SpringCloud Alibaba Nacos服务注册和配置中心 1.简介 2.各种注册中心比较 3.下载安装 4.Nacos Discovery服务注册中心 &#xff08;1&#xff09; 基于 Nacos 的服务提供者 &#xf…

Ollama vs VLLM:大模型推理性能全面测评!

最近在用本地大模型跑实验&#xff0c;一开始选择了ollama,分别部署了Qwen2.5-14B和Qwen2.5-32B&#xff0c;发现最后跑出来的实验效果很差&#xff0c;一开始一直以为prompt的问题&#xff0c;尝试了不同的prompt&#xff0c;最后效果还是一直不好。随后尝试了vllm部署Qwen2.5…

.NET9 - 新功能体验(一)

被微软形容为“迄今为止最高效、最现代、最安全、最智能、性能最高的.NET版本”——.NET 9已经发布有一周了&#xff0c;今天想和大家一起体验一下新功能。 此次.NET 9在性能、安全性和功能等方面进行了大量改进&#xff0c;包含了数千项的修改&#xff0c;今天主要和大家一起体…

LeetCode 144.二叉树的前序遍历

题目&#xff1a;给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 思路&#xff1a;根 左 右 代码&#xff1a; /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNod…

【论文阅读】WGSR

0. 摘要 0.1. 问题提出 1.超分辨率(SR)是一个不适定逆问题&#xff0c;可行解众多。 2.超分辨率(SR)算法在可行解中寻找一个在保真度和感知质量之间取得平衡的“良好”解。 3.现有的方法重建高频细节时会产生伪影和幻觉&#xff0c;模型区分图像细节与伪影仍是难题。 0.2. …

游戏引擎学习第21天

虽然没有上一节的难但是内容也很多 关于实现和使用脚本语言 以下是详细复述&#xff1a; 许多人经常问一个问题&#xff0c;反复问过好几次&#xff0c;那就是&#xff1a;是否会在项目中实现脚本语言。这个问题的具体形式通常是&#xff1a;你们会使用脚本语言吗&#xff1…

NVR接入录像回放平台EasyCVR视频融合平台加油站监控应用场景与实际功能

在现代社会中&#xff0c;加油站作为重要的能源供应点&#xff0c;面临着安全监管与风险管理的双重挑战。为应对这些问题&#xff0c;安防监控平台EasyCVR推出了一套全面的加油站监控方案。该方案结合了智能分析网关V4的先进识别技术和EasyCVR视频监控平台的强大监控功能&#…

springboot vue工资管理系统源码和答辩PPT论文

人类现已迈入二十一世纪&#xff0c;科学技术日新月异&#xff0c;经济、资讯等各方面都有了非常大的进步&#xff0c;尤其是资讯与网络技术的飞速发展&#xff0c;对政治、经济、军事、文化等各方面都有了极大的影响。 利用电脑网络的这些便利&#xff0c;发展一套工资管理系统…