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

ops/2024/11/24 15:55:39/

文章目录

  • 线程是什么?
    • 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 {@Overridepublic 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接口

    @Overridepublic 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;}@Overridepublic 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(){@Overridepublic 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(){@Overridepublic 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.ppmy.cn/ops/136334.html

相关文章

HTML5和CSS3新增特性

HTML5的新特性 HTML5新增的语义化标签 HTML5 的新增特性主要是针对于以前的不足,增加了一些新的标签、新的表单和新的表单属性等。 这些新特性都有兼容性问题,基本是 IE9 以上版本的浏览器才支持,如果不考虑兼容性问题,可以大量…

数据分析-51-时间序列分解之局部均值分解LMD

文章目录 1 时间序列模态分解1.1 模态分解的概念1.2 模态分解的作用1.3 常用的模态分解方法1.4 模态分解的常用库2 局部均值分解LMD2.1 LMD的流程2.2 加载数据集2.2.1 数据重采样2.2.2 原始数据可视化2.3 局部均值分解LMD3 参考附录1 时间序列模态分解 1.1 模态分解的概念 时…

代码随想录算法训练营第五十五天|Day55 图论

寻找存在的路径 https://www.programmercarl.com/kamacoder/0107.%E5%AF%BB%E6%89%BE%E5%AD%98%E5%9C%A8%E7%9A%84%E8%B7%AF%E5%BE%84.html 思路 #include <stdio.h> #include <stdlib.h>#define MAX_NODES 101// 邻接表的节点结构 typedef struct Node {int verte…

设计模式-创建型-建造者模式

1.概念 建造者设计模式&#xff08;Builder Design Pattern&#xff09;是一种创建型设计模式&#xff0c;它通过将一个复杂对象的构建过程与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 2.作用 用于简化对复杂对象的创建 3.应用场景 当我们有一个非…

从 HTML 到 CSS:开启网页样式之旅(二)—— 深入探索 CSS 选择器的奥秘

从 HTML 到 CSS&#xff1a;开启网页样式之旅&#xff08;二&#xff09;—— 深入探索 CSS 选择器的奥秘 前言一、CSS基本选择器1. 通配选择器2. 元素选择器3. 类选择器4. id选择器5.基本选择器总结 二、CSS复合选择器1. 后代选择器2. 子选择器3. 相邻兄弟选择器4.交集选择器5…

Spring框架深度剖析:特性、安全与优化

文章目录 Spring框架简介主要特性1. 依赖注入&#xff08;Dependency Injection, DI&#xff09;2. 面向切面编程&#xff08;Aspect-Oriented Programming, AOP&#xff09;3. 声明式事务管理4. 强大的MVC框架5. 集成测试支持6. 多种数据访问技术的支持 安全性1. 认证&#xf…

网络安全-企业环境渗透2-wordpress任意文件读FFmpeg任意文件读

一、 实验名称 企业环境渗透2 二、 实验目的 【实验描述】 操作机的操作系统是kali 进入系统后默认是命令行界面 输入startx命令即可打开图形界面。 所有需要用到的信息和工具都放在了/home/Hack 目录下。 本实验的任务是通过外网的两个主机通过代理渗透到内网的两个主机。…

鸿蒙NEXT开发案例:数字转中文大小写

【引言】 本应用的主要功能是将用户输入的数字转换为中文的小写、大写及大写金额形式。用户可以在输入框中输入任意数字&#xff0c;点击“示例”按钮可以快速填充预设的数字&#xff0c;点击“清空”按钮则会清除当前输入。转换结果显示在下方的结果区域&#xff0c;每个结果…